您的位置:首页 > 编程语言 > Java开发

【二】Spring AOP 最全源码详解之创建代理对象

2019-03-09 15:34 357 查看
版权声明:本博客原创文章遵循CC BY-NC-SA 2.5 CN 协议 https://blog.csdn.net/wuyuwei/article/details/88357698

目录

1. 判断是否需要被代理

2. 创建代理类createProxy

3. 附录:本工程项目文件

前在《【九】Spring IoC 最全源码详解之initializeBean》中提到过创建Spring AOP代理对象的留下就在执行bean后置处理器的postProcessAfterInitialization方法中。更具体一点是执行AnnotationAwareAspectJAutoProxyCreator处理器的父类AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization的方法中完成的。

[code]protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

invokeInitMethods(beanName, wrappedBean, mbd);

if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

我们具体来看看它的方法实现:

[code]public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 如果是普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// earlyProxyReferences中缓存的是已经创建好的代理对象
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

getCacheKey的作用是:如果是对于普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName。然后根据cacheKey去earlyProxyReferences这个缓存中看看该代理对象是否已经被创建过了,如果创建过直接返回bean。否则进入wrapIfNecessary方法。

1. 判断是否需要被代理

[code]protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 也是看看有没有缓存,有缓存对象就直接返回了。
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果该bean不需要被代理,则直接返回原始的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;
}

首先也是看看有没有缓存,有缓存对象就直接返回了。然后尝试再advisedBeans缓存中获取要代理的原始对象,如果它不需要被代理的话也直接返回原始对象。值得注意的是在IOC启动过程中,第一次进入advisedBeans这个缓存中是没有值的。isInfrastructureClass和shouldSkip在上一篇文章已经分析过,这里不再赘述。其对应的if分支是不会进入。重点放在方法getAdvicesAndAdvisorsForBean,该方法又主要委托findEligibleAdvisors来实现寻找advisor的逻辑,所以我们直接来看findEligibleAdvisors

[code]protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有已经解析完成的advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 根据beanClass过滤candidateAdvisors中的advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

findCandidateAdvisors将找到的advisor放入到candidateAdvisors中(详细分析请见上一篇文章)。随后在findEligibleAdvisors中根据beanClass过滤除适用的advisor。最终执行的方法是在AopUtils#findAdvisorsThatCanApply

[code]public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}

Advisor分为IntroductionAdvisor和PointcutAdvisor两种,我们使用的绝大部分Advisor都是PointcutAdvisor。canApply方法可以用来确认所给定的类上advisor是否可以被应用。最后返回过滤后可以被应用在给定类上的advisors。以OperationUtil.class为例,OperationAop.class中的三个Advice都可以被作用在OperationUtil.class上;而其余的类则一个也没有。

返回到findEligibleAdvisors中执行extendAdvisors方法,该方法会添加一个DefaultPointcutAdvisor到eligibleAdvisors中。如果使用AspectJ的切点表达式,则会使用AspectJExpressionPointcutAdvisor;如果使用名称匹配切点的方式,则用NameMatchMethodPointcutAdvisor;如果使用正则匹配切点的方式,则使用RegexpMethodPointcutAdvisor;如果使用其他方式,比如用户自定义切点的方式,那么就使用DefaultPointcutAdvisor。随后的排序会将刚刚添加进入的DefaultPointcutAdvisor排到第一个位置。

最终wrapIfNecessary方法Object[] specificInterceptors得到的结果就是刚刚返回的eligibleAdvisors。如果specificInterceptors不为null,就advisedBeans.put(cacheKey, Boolean.TRUE),将对应的bean添加到全局的advisedBeans中,并且value是true,代表该bean需要被代理。接下来就是通过createProxy方法创建代理类了。

2. 创建代理类createProxy

[code]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();
proxyFactory.copyFrom(this);

if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTarget
20000
Class(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 就是把specificInterceptors中的advisors和commonInterceptors中的拦截器合并(如果有的话)在一起封装成Advisor返回
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 将advisors和源对象设置到proxyFactory上
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 真正去创建代理对象了
return proxyFactory.getProxy(getProxyClassLoader());
}

exposeTargetClass这个步骤看了很久才明白Spring的意思。下面简单说下我的理解:

走到这里就已经能肯定代理类是会创建的了,所以可以提前“曝光”它的原始类。expose一词是公之于众的意思,在这里也就是告诉其他bean:大家来看看啊,当前正在创建的bean(比如是OperationUtil)即将要青蛙变王子了!

怎么做到公之于众呢?Spring的做法是在方法内部在正常创建的bean的bd(全写是BeanDefinition)中设置上一个属性<"originalTargetClass", OperationUtil.class>。而bd是存放在bdmap中,bdmap又是由bean工厂直接管理。创建bean必须要有bean工厂的参与,这样就意味着只要在bd中增加一个属性就相当于对其他bean可见了。

接下来创建一个ProxyFactory,并从当前bean后置处理器AnnotationAwareAspectJAutoProxyCreator中获取参数初始化自身。然后确定代理方式是通过接口代理还是类继承代理。通过接口代理使用JDK自身提供的动态代理就能实现,而其他的代理只能通过Cglib实现动态代理。proxyTargetClass默认是false使用JDK代理,如果是true则使用Cglib。

接下来的buildAdvisors是把specificInterceptors中的advisors和commonInterceptors中的拦截器合并(如果有的话)在一起封装成Advisor返回。随后在proxyFactory对象上进行设置。这里targetSource就是被代理的bean对象。

最后就到了执行真正的创建逻辑了。

[code]public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
// 获得被代理对象的类型
Class<?> targetClass = config.getTargetClass();
// 如果对象类型是接口,或者是JAVA的动态代理类,那么就调用JDK的动态代理方法生成代理对象
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用CGLIB生成代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

// JDK动态代理
public Object getProxy(@Nullable ClassLoader classLoader) {
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

从config中拿出被代理对象的类型,然后判断该对象是否是接口或者是java的动态代理类。如果是则创建JdkDynamicAopProxy工厂,否则创建Cglib的ObjenesisCglibAopProxy工厂。随后调用对应Proxy工厂的getProxy方法创建代理对象。以创建JDK动态代理为例,最终会调用JAVA提供的Proxy.newProxyInstance动态代理方法代理对象后返回。

到此,Spring AOP的代理对象创建过程源码就分析的差不多了。总结一下:在bean的创建过程中,先实例化完成被代理对象并完成依赖注入后,进行到初始化bean的阶段。利用bean后置处理器AnnotationAwareAspectJAutoProxyCreator的applyBeanPostProcessorsAfterInitialization方法实现对目标对象的代理任务。任务进行过程中大致可以分为2步:1.获取之前已经解析好的advisors,逐个判断目标代理对象是否可以适用。2.如果使用则创建代理工厂,然后判断代理类型是通过接口还是通过类,如果是通过接口就由JDK动态代理生成代理对象,否则使用 Cglib来做这件事。

3. 附录:本工程项目文件

[code]@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HodayDouble {
}
[code]@Aspect
@Component
public class OperationAop {

@Pointcut("@annotation(com.Hodey.analyseaop.anno.HodayDouble)")
public void doCut(){}

@Around("doCut()")
public int doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object[] args = proceedingJoinPoint.getArgs();
int i = (int) args[0];
int j = (int) args[1];
System.out.println("入参:i:" + i);
System.out.println("入参:j:" + j);
System.out.println("before around");
int result = (int) proceedingJoinPoint.proceed();
System.out.println("after around");
System.out.println("原始结果:" + result);

result = result * 2;
System.out.println("代理结果:" + result);
return result;
}

@Before("doCut()")
public void doBefore(){
System.out.println("@Before print");
}

@After("doCut()")
public void doAfter(){
System.out.println("@After print");
}
}
[code]@Service("service")
public class OperationService {

@Autowired
private OperationUtil ops;

public int add(int i , int j){
return ops.add(i,j);
}
}
[code]@Component
public class OperationUtil {

@HodayDouble
public int add(int i, int j){
int result = i + j;
return result;
}
}
[code]@ComponentScan("com.Hodey")
@EnableAutoConfiguration
public class AnalyseAopApplication {

public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnalyseAopApplication.class);
OperationService opsService = (OperationService) ctx.getBean("service");
int result = opsService.add(2,3);
System.out.println("最终结果:" + result);
}
}

执行结果:

[code]入参:i:2
入参:j:3
before around
@Before print
after around
原始结果:5
代理结果:10
@After print
最终结果:10

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: