在收集完切面,当切面不为空,则生成代理对象。
spring中有两种动态代理,一种是jdk动态代理,还有一种是cglib动态代理,默认采用的是jdk动态代理,看spring源码设计:
在@EnableAspectJAutoProxy注解中,通过属性proxyTargetClass控制采用哪种动态代理,但jdk动态代理需要类实现接口,才能被代理,那如果没有实现接口怎么被代理?
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
//把AnnotationAwareAspectJAutoProxyCreator中的某些属性copy到proxyFactory中
proxyFactory.copyFrom(this);
//校验采用哪种代理
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//组装advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//把advisor加入到proxyFactory
proxyFactory.addAdvisors(advisors);
//把被代理对象加入到proxyFactory
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//获取代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
接下来组装advisor:
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// Handle prototypes correctly...
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<>();
.....
//将commonInterceptors 放入allInterceptors
.....
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
先看这个代码:
Advisor[] commonInterceptors = resolveInterceptorNames();
接下来根据源码设置一个自定义advice:
@Component
public class AdviceTest implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("自定义advice");
return methodInvocation.proceed();
}
}
//开启切面
@EnableAspectJAutoProxy
@Component
@Aspect
public class AspectAnnotation {
//设置表达式路径在test包下
@Pointcut(value = "execution(public * com.study.dongsq.test.*.*(..))")
public void pc(){}
@Before("pc()")
public void before(){
System.out.println("==============================");
}
}
@Component
public class SetAdvice implements BeanPostProcessor, PriorityOrdered {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof AnnotationAwareAspectJAutoProxyCreator){
AnnotationAwareAspectJAutoProxyCreator creator = (AnnotationAwareAspectJAutoProxyCreator) bean;
//将自定义advice设置到interceptorNames中
creator.setInterceptorNames("adviceTest");
}
return bean;
}
@Override
public int getOrder() {
return 0;
}
}
//在test包下定义一个Test类
@Component
public class Test {
public void test1(){}
}
接下来会根据自定义的advice生成一个默认的切面:DefaultPointcutAdvisor
这样就有了三个切面:
第一个是自定义advice生成的默认切面,第二个是对有@Aspect注解切面添加了一个默认的切面,第三个是pointcut表达式拦截到Test类产生的切面。
那上图中的第二个切面ExposeInvocationInterceptor.ADVISOR的作用是什么?
看这个切面的源码:
是new了一个DefaultPointCutAdvisor,将自己作为通知传入,在DefaultPointCutAdvisor中pointcut类和方法的匹配始终返回true,表示对所有的类和方法都拦截。
通过上图的invoke方法可以看到,将MethodInvocation放入了threadLocal当中,意义是可以不用通过入参MethodInvocation来获取被代理对象的方法和入参等信息,可以通过threadLocal直接获取。
组装advisors之后是对proxyFactory的组装,接下来是获取代理对象:
.....
return proxyFactory.getProxy(getProxyClassLoader());
.....
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
.....
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
判断采用哪种代理一般根据两个情况,一种是proxyTargetClass的值,另一种是被代理类有无接口,proxyTargetClass默认为false,采用jdk动态代理,但是被代理类没有实现接口或者接口中没有方法,proxyTargetClass也会被设置成true,改成cglib代理。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/13823.html