spring源码之代理生成

在收集完切面,当切面不为空,则生成代理对象。

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代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值