AOP实现原理
深入理解Spring AOP的实现机制,掌握代理模式和切面织入原理,理解JDK动态代理和CGLIB代理的区别,掌握通知类型、切点表达式等核心概念。
📋 AOP概览
AOP(Aspect-Oriented Programming,面向切面编程)是Spring的核心功能之一,通过代理模式实现横切关注点的分离。
🎯 一、代理模式基础
1.1 代理模式概述
代理模式为对象提供一个代理,以控制对这个对象的访问。Spring AOP使用代理模式来实现横切关注点。
代理模式的角色:
- Subject(抽象主题):定义代理和真实对象的共同接口
- RealSubject(真实主题):实现业务逻辑的具体对象
- Proxy(代理):包含对真实主题的引用,控制对真实主题的访问
1.2 代理模式类型
Spring AOP支持两种代理方式:
- JDK动态代理:基于接口实现
- CGLIB代理:基于类继承实现
代理选择规则:
java
// DefaultAopProxyFactory.createAopProxy
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() ||
hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果目标类是接口或者是代理类,使用JDK动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用CGLIB代理
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}🎯 二、JDK动态代理
2.1 JDK动态代理原理
JDK动态代理使用java.lang.reflect.Proxy类在运行时动态创建代理对象。
核心类:
- Proxy:代理类工厂
- InvocationHandler:调用处理器接口
示例代码:
java
public interface UserService {
void saveUser(User user);
User getUser(Long id);
}
public class UserServiceImpl implements UserService {
@Override
public void saveUser(User user) {
System.out.println("保存用户:" + user);
}
@Override
public User getUser(Long id) {
System.out.println("获取用户:" + id);
return new User();
}
}
// 调用处理器
public class UserServiceInvocationHandler implements InvocationHandler {
private Object target;
public UserServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("前置处理");
Object result = method.invoke(target, args);
System.out.println("后置处理");
return result;
}
}
// 创建代理
UserService target = new UserServiceImpl();
InvocationHandler handler = new UserServiceInvocationHandler(target);
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);
proxy.saveUser(new User());2.2 JdkDynamicAopProxy
Spring AOP中的JDK动态代理实现:
java
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
private final AdvisedSupport advised;
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(
this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 如果方法不是equals/hashCode/toString,或者是配置器方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 如果需要暴露代理到AopContext
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(
method, targetClass);
// 如果没有拦截器,直接调用目标方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建方法调用对象
MethodInvocation invocation = new ReflectiveMethodInvocation(
proxy, target, method, args, targetClass, chain);
// 执行拦截器链
retVal = invocation.proceed();
}
// 获取方法返回值类型
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE &&
returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
}invoke方法流程:
🎯 三、CGLIB代理
3.1 CGLIB代理原理
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,通过继承目标类来创建代理对象。
CGLIB代理的特点:
- 不需要接口
- 通过继承目标类实现
- 不能代理final类和final方法
示例代码:
java
public class UserService {
public void saveUser(User user) {
System.out.println("保存用户:" + user);
}
}
// 方法拦截器
public class UserServiceMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("前置处理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置处理");
return result;
}
}
// 创建代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new UserServiceMethodInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.saveUser(new User());3.2 ObjenesisCglibAopProxy
Spring AOP中的CGLIB代理实现:
java
class ObjenesisCglibAopProxy extends CglibAopProxy {
public ObjenesisCglibAopProxy(AdvisedSupport config) {
super(config);
}
@Override
protected Object createProxyClassAndInstance(Enhancer enhancer,
Callback[] callbacks) {
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = null;
if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass,
enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}
if (proxyInstance == null) {
try {
proxyInstance = ReflectionUtils.accessibleConstructor(
proxyClass).newInstance();
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy", ex);
}
}
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
}🎯 四、通知类型
4.1 通知接口
Spring AOP定义了多种通知接口:
- BeforeAdvice:前置通知
- AfterAdvice:后置通知
- AroundAdvice:环绕通知
- ThrowsAdvice:异常通知
4.2 前置通知
MethodBeforeAdvice接口:
java
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, @Nullable Object target)
throws Throwable;
}实现示例:
java
public class LogBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("方法执行前:" + method.getName());
}
}4.3 后置通知
AfterReturningAdvice接口:
java
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method,
Object[] args, @Nullable Object target) throws Throwable;
}4.4 环绕通知
MethodInterceptor接口:
java
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}实现示例:
java
public class LogAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("方法执行前:" + invocation.getMethod().getName());
try {
Object result = invocation.proceed();
System.out.println("方法执行后:" + invocation.getMethod().getName());
return result;
}
catch (Exception e) {
System.out.println("方法执行异常:" + e.getMessage());
throw e;
}
}
}🎯 五、切点表达式
5.1 切点表达式语法
AspectJ切点表达式用于匹配需要被拦截的方法。
常用表达式:
java
// 匹配所有方法
execution(* *(..))
// 匹配指定包下的所有方法
execution(* com.example.service.*.*(..))
// 匹配指定类的方法
execution(* com.example.service.UserService.*(..))
// 匹配指定方法
execution(* com.example.service.UserService.saveUser(..))
// 匹配指定参数类型的方法
execution(* com.example.service.UserService.saveUser(com.example.model.User))
// 匹配指定注解的方法
@annotation(com.example.annotation.Log)5.2 AspectJExpressionPointcut
Spring使用AspectJExpressionPointcut来解析切点表达式:
java
public class AspectJExpressionPointcut extends AbstractExpressionPointcut
implements ClassFilter, MethodMatcher {
private final PointcutExpression pointcutExpression;
public AspectJExpressionPointcut(String expression, Class<?> pointcutDeclarationScope) {
this.pointcutExpression = buildPointcutExpression(expression,
pointcutDeclarationScope);
}
@Override
public boolean matches(Class<?> targetClass) {
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
ShadowMatch shadowMatch = getShadowMatch(method, targetClass);
return shadowMatch.alwaysMatches();
}
}🎯 六、AOP代理创建流程
6.1 代理创建时机
AOP代理在Bean创建过程中创建:
6.2 AbstractAutoProxyCreator
AbstractAutoProxyCreator负责自动创建AOP代理:
java
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass,
String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 获取通知
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName)
throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors,
new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}📖 学习资源
视频教程
书籍推荐
- 《Spring源码深度解析》 - 郝佳
- 《Spring技术内幕》 - 计文柯
网站资源
✅ 学习检查清单
- [ ] 已理解代理模式原理
- [ ] 已理解JDK动态代理实现
- [ ] 已理解CGLIB代理实现
- [ ] 已理解两种代理的区别
- [ ] 已理解通知类型
- [ ] 已理解切点表达式
- [ ] 已理解AOP代理创建流程
- [ ] 已理解拦截器链的执行机制
- [ ] 已绘制AOP架构图
- [ ] 已总结核心知识点
上一章节:IoC容器深度解析
下一章节:事务管理机制
返回目录:Spring源码深度解析