致敬读者
博主相关
文章前言
控制反转(IoC):
依赖注入(DI):
// 1. 构造器注入(推荐)
public class UserService {
private final UserRepository repo;
@Autowired
public UserService(UserRepository repo) {
this.repo = repo;
}
}
// 2. Setter注入
public class OrderService {
private PaymentGateway gateway;
@Autowired
public void setGateway(PaymentGateway gateway) {
this.gateway = gateway;
}
}
// 3. 字段注入(不推荐)
public class ProductService {
@Autowired
private InventoryService inventory;
}
Q1:IoC和DI的区别与联系?
Q2:构造器注入为什么被推荐?
Q3:Spring如何解决循环依赖?
singletonObjects
)earlySingletonObjects
)singletonFactories
)Q4:@Autowired和@Resource的区别?
特性 | @Autowired |
@Resource |
---|---|---|
来源 | Spring框架 | JSR-250标准 |
注入方式 | 按类型(可配合@Qualifier) | 按名称(可指定name属性) |
支持参数 | required | name, type |
适用场景 | Spring专属项目 | 需要跨框架兼容性 |
核心组件:
通知类型:
@Aspect
public class LoggingAspect {
// 前置通知
@Before("execution(* com.service.*.*(..))")
public void logBefore(JoinPoint jp) {
System.out.println("Method: " + jp.getSignature().getName());
}
// 环绕通知(最强大)
@Around("@annotation(com.audit.Loggable)")
public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
long duration = System.currentTimeMillis() - start;
System.out.println("Duration: " + duration + "ms");
return result;
}
}
Q1:Spring AOP和AspectJ的区别?
特性 | Spring AOP | AspectJ |
---|---|---|
织入方式 | 运行时代理 | 编译时/加载时织入 |
性能 | 有运行时开销 | 无运行时开销 |
连接点支持 | 仅方法级别 | 方法、构造器、字段等 |
依赖 | 轻量级,内置于Spring | 需要额外编译器/类加载器 |
适用场景 | 普通应用 | 高性能、复杂切面需求 |
Q2:JDK动态代理和CGLIB如何选择?
Proxy.newProxyInstance()
Q3:如何实现自定义注解的切面?
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuditLog {
String action();
}
@Aspect
@Component
public class AuditAspect {
@AfterReturning(
value = "@annotation(auditLog)",
returning = "result"
)
public void audit(AuditLog auditLog, Object result) {
String action = auditLog.action();
// 保存审计日志到DB
auditRepository.save(new AuditRecord(action, result));
}
}
// 使用示例
@Service
public class OrderService {
@AuditLog(action = "PLACE_ORDER")
public Order createOrder(OrderRequest request) {
// 业务逻辑
}
}
事务管理(@Transactional实现原理):
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
timeout = 30)
public void transfer(Account from, Account to, BigDecimal amount) {
// 使用AOP代理实现:
// 1. 获取连接
// 2. 设置隔离级别
// 3. try{业务逻辑} catch{回滚} finally{关闭连接}
}
安全审计:
@Before("within(@org.springframework.stereotype.Controller *)")
public void logControllerAccess(JoinPoint jp) {
String user = SecurityContextHolder.getContext().getAuthentication().getName();
logger.info("User: " + user + " accessed: " + jp.getSignature());
}
Q1:如何选择代理方式?
Q2:AOP中的设计模式?
代理模式:
java.lang.reflect.Proxy
net.sf.cglib.proxy.Enhancer
责任链模式:
public interface MethodInterceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
// 拦截器链执行
public class ReflectiveMethodInvocation implements MethodInvocation {
private final List<MethodInterceptor> interceptors;
private int currentInterceptorIndex = -1;
public Object proceed() {
if (this.currentInterceptorIndex == this.interceptors.size() - 1) {
return invokeJoinpoint();
}
MethodInterceptor interceptor =
interceptors.get(++this.currentInterceptorIndex);
return interceptor.invoke(this);
}
}
Q3:如何调试AOP不生效问题?
检查切点表达式:
// 打印所有被代理的Bean
@Bean
public CommandLineRunner aopDebug(ApplicationContext ctx) {
return args -> {
String[] beans = ctx.getBeanDefinitionNames();
Arrays.stream(beans)
.filter(name -> ctx.getBean(name).getClass().getName().contains("$$"))
.forEach(System.out::println);
};
}
确认代理方式:
// 检查Bean是否被代理
if (AopUtils.isAopProxy(bean)) {
System.out.println(bean + " is proxied");
}
DI最佳实践:
@Qualifier
解决歧义依赖@Autowired(required=false)
AOP避坑指南:
@Around
(必须调用proceed())// 错误示例(自调用导致AOP失效)
public void process() {
this.validate(); // 不会被AOP拦截
}
@Transactional
public void validate() { /* ... */ }
// 解决方案:通过代理调用
@Autowired
private ApplicationContext context;
public void process() {
context.getBean(this.getClass()).validate();
}
性能优化:
// 优化切点表达式
@Pointcut("within(com.service..*) && execution(public * *(..))")
public void servicePublicMethods() {}
// 使用条件编译(AspectJ)
@Aspect
@ConditionalOnExpression("${aop.enabled:true}")
public class PerformanceAspect { /* ... */ }
Q1:Spring如何整合IoC和AOP?
AbstractAutowireCapableBeanFactory.createBean()
AbstractAutoProxyCreator.postProcessAfterInitialization()
ProxyFactory.getProxy()
Q2:如何实现跨切面数据传递?
// 使用ThreadLocal
public class RequestContext {
private static final ThreadLocal<Map<String, Object>> context = new ThreadLocal<>();
public static void put(String key, Object value) {
getContextMap().put(key, value);
}
}
// 前置切面
@Before("@within(org.springframework.web.bind.annotation.RestController)")
public void initContext() {
RequestContext.put("startTime", System.currentTimeMillis());
}
// 后置切面
@AfterReturning("@within(org.springframework.web.bind.annotation.RestController)")
public void logContext() {
long start = (long) RequestContext.get("startTime");
System.out.println("Request took: " + (System.currentTimeMillis() - start) + "ms");
}
Q3:如何扩展Spring AOP?
实现自定义Pointcut
:
public class CustomPointcut extends StaticMethodMatcherPointcut {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return method.isAnnotationPresent(CustomAnnotation.class);
}
}
创建自定义Advisor
:
@Bean
public Advisor customAdvisor() {
CustomPointcut pointcut = new CustomPointcut();
Advice advice = new CustomInterceptor();
return new DefaultPointcutAdvisor(pointcut, advice);
}
掌握这些核心概念和实战技巧,不仅能应对面试中的深度问题,更能构建高内聚、低耦合的企业级应用。
文末寄语