参考链接:http://www.importnew.com/28342.html
静态代理:编译期将代理方法植入目标方法
Jdk动态代理:对于实现接口的类,采用jdk动态代理实现的接口,所以不是接口中定义的方法没办法被代理。JDK动态代理的核心是InvocationHandler接口和Proxy类。
Cglib动态代理:对于没有实现接口的类,采用cglib代理,通过动态生成目标类的子类进行代理,所以private方法,final方法不能被代理。我觉得关键类是CglibAopProxy和MethodInterceptor。
在spring中bean加载过程文章中,我简单分析了一下加载过程,但是在最后设置属性的地方放过了,这个地方是进行AOP代理的入口。
在AbstractAutowireCapableBeanFactory类的doCreateBean方法中
......
try {
this.populateBean(beanName, mbd, instanceWrapper);//设置属性,依赖关系
exposedObject = this.initializeBean(beanName, exposedObject, mbd);//对bean进行判断是否要创建代理
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
......
一路debug下去之后,在AbstractAutoProxyCreator类中
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;
}
// Create proxy if we have advice.
//这个查找bean对象适用的advisor,并做排序,如果有advisor,那么就创建代理
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;
}
一部分advisor是我们通过注解自定义的,一部分advisor是通过实现MethodMatcher接口的形式,静态的通知,比如Transactional注解,下面的参考链接是Transactional注解的一个解析过程
参考链接:https://blog.youkuaiyun.com/dalinsi/article/details/53215041
创建代理的接口类AopProxy,有两个实现,一个是cglib,一个是jdk,我测试是在CglibAopProxy中创建代理,这里看出是子类代理,将父类适用的advisor植入进去。
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
......
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
......
}
AOP切面失效案例:
测试代码如下:
有两个Service,PringLog注解上有设置切面,会打印相关日志。
@Service
public class BManager {
@PrintLog(logContent = "I'm BService")
public void functionA(){
System.out.println("functionA is done");
functionB();
}
@PrintLog(logContent = "I'm BService")
public void functionB(){
System.out.println("functionB is done");
}
@PrintLog(logContent = "I'm BService")
public void functionC(){
System.out.println("functionC is done");
}
}
@Service
public class AManager {
@Resource
private BManager bManager;
@PrintLog(logContent = "I'm AService")
public void functionA(){
System.out.println("functionA is done");
bManager.functionA();
}
@PrintLog(logContent = "I'm AService")
public void functionD(){
System.out.println("functionD is done");
bManager.functionB();
bManager.functionC();
}
}
测试1:
aManager.functionA();
结果:
enter interceptorstart print log :I'm AService
functionA is done
enter interceptorstart print log :I'm BService
functionA is done
functionB is done
测试2
aManager.functionD();
结果:
enter interceptorstart print log :I'm AService
functionD is done
enter interceptorstart print log :I'm BService
functionB is done
enter interceptorstart print log :I'm BService
functionC is done
在代用的时候,可以明确看到,我们不是直接调用AManager对象,而是调用cglib生成的代理类。
出现测试2的结果其实我们很好理解,但是测试1的情况,可能有朋友不理解。在进入BManager的A方法时,是通过子类代理进入的,这个时候子类代理前后是被植入了print代码的。但是在进入A方法后,调用本类的B方法,不是通过子类代理调用的, 而是通过父类直接调用,父类中是没有植入print代码的,所以不会有相应的日志
待更新完善…