24.AOP的第一个时机之resolveBeforeInstantiation


highlight: arduino-light

在spring aop中,如果我们的类属符合如下条件:被切面的pointcut匹配到、或者属于自定义的Advisor接口实现类,那么spring在bean完成实例化之后,会为类生成代理对象。这是众所周知的aop流程。

此外,spring还为我们提供了TargetSourceCreator接口,该接口的功能是:在bean实例化之前,就为类生成代理。 现在我们通过查看源码的方式,来了解该接口的功能。

创建代理

doGetBean

在循环依赖中我们讲了spring实例化bean的入口,refresh->finishBeanFactoryInitialization->preInstantiateSingletons->getBean->doGetBean,看doGetBean中的如下代码

java if (mbd.isSingleton()) { // 实例化bean sharedInstance = getSingleton(beanName, () -> { try { // 真正的完成bean的创建 return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }

createBean

createBean(beanName, mbd, args);方法真正的完成了bean的实例化,包括循环依赖、AOP、生命周期等。

所谓的AOP无非就是将bean加强,在bean的方法前后加上其他的方法而已,bean的class在虚拟机启动的时候就加载到JVM里了,我们不会通过修改class来动态扩展bean的功能,但是可以新生成一个类(动态代理类),这个类呢,包含了bean的所有功能,同时又进行了加强,然后将这个动态代理类实例化,替换掉原有的bean,最后放到spring单例池中。

如果你的类没有被其他类依赖,那么可以在doCreateBean之前就创建好代理对象。

java //给Bean后置处理器一个机会,返回一个替代目标对象的代理对象。 //就在这里 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) {    //注意如果有 InstantiationAwareBeanPostProcessor类型的接口    //并返回了自定义对象 这里会直接返回    return bean; } //如果上面直接返回了bean 下面的doCreateBean就不会执行 Object beanInstance = doCreateBean(beanName, mbdToUse, args);

注意此时还没后面的bean初始化代码,这里AOP的准备工作,AOP实现是靠BeanPostProcessor后置处理器完成的。

BeanFactoryPostProcessor和BeanPostProcessors两者有啥区别?

BeanFactoryPostProcessor干预BeanDefinition的生成,而BeanPostProcessors干预bean的实例化。

java // 给Bean后置处理器一个机会,返回一个替代目标对象的代理对象。 @Nullable protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; //如果尚未被解析 if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // Make sure bean class is actually resolved at this point. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { //调用InstantiationAwareBeanPostProcessor的 //postProcessBeforeInstantiation //参数是Class bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); //这里返回的是null if (bean != null) { //调用BeanPostProcessor的 postProcessAfterInitialization //注意是BeanPostProcessor bean = applyBeanPostProcessorsAfterInitialization (bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }

这个resolveBeforeInstantiation()方法的意义到底是什么?

其实很简单,它的意思就是说,如果我们指定了targetSource,那么可以在这里创建一个代理直接返回,就不需要走下边的实例化和初始化阶段了,因为指定了targetSource后,这个bean就由开发人员自己负责完成创建了。而如果没有指定targetSource,那么就按照正常流程往下执行bean的实例化和初始化,说白了就是人家注释上说的:“给你一个返回代理的机会”。

java protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { //for循环,拿到所有的BeanPostProcessors。 for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { //判断是InstantiationAwareBeanPostProcessor //强转为InstantiationAwareBeanPostProcessor InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; //调用InstantiationAwareBeanPostProcessor的 //postProcessBeforeInstantiation方法 Object result = ibp.postProcessBeforeInstantiation (beanClass, beanName); if (result != null) { return result; } } } //如果没有实现自定义的InstantiationAwareBeanPostProcessor //这里返回的是null return null; } 注意这里收集到的是InstantiationAwareBeanPostProcessor InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口。如果applyBeanPostProcessorsBeforeInstantiation方法返回bean不为空,则实例化结束直接返回resolveBeforeInstantiation方法的返回值。不会执行下面的doCreateBean方法。

spring会遍历所有BeanPostProcessor,这么多后置处理器具体生成代理用到的是哪个?

答:AnnotationAwareAspectJAutoProxyCreator。

AnnotationAwareAspectJAutoProxyCreator继承自AbstractAutoProxyCreator。AbstractAutoProxyCreator是InstantiationAwareBeanPostProcessor类型,并且重写了postProcessBeforeInstantiation方法,所以此时进入AbstractAutoProxyCreator的方法,postProcessBeforeInstantiation方法如下:

postProcessBeforeInstantiation

此时生成代理的第一个时机都出现了,在postProcessBeforeInstantiation方法中生成代理

java   @Override    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {        Object cacheKey = getCacheKey(beanClass, beanName); ​        if (!StringUtils.hasLength(beanName) ||           !this.targetSourcedBeans.contains(beanName)) {                        //advisedBeans是一个集合,用来保存不需要代理的类。比如我们上面定义的切面            //本身是不需要被代理的,还有加了@Configuration注解的Config配置类,            //是不需要代理的,Config其实已经被代理了,之前讲过。            if (this.advisedBeans.containsKey(cacheKey)) {                return null;           }            //isInfrastructureClass(beanClass)            //判断我们这个业务类是否需要被代理,进入isInfrastructureClass代码            //判断Advice、Pointcut、Advisor是否是beanClass的超类或者超接口            //shouldSkip(beanClass, beanName)            //主要是判断beanName不为空且不是original instance            //2个条件都是false 说明需要代理            if (isInfrastructureClass(beanClass)               || shouldSkip(beanClass, beanName)) {                //不需要代理                this.advisedBeans.put(cacheKey, Boolean.FALSE);                return null;           }       } //这里会做判断 如果 targetSource        //如果有自定义TargetSource        //将当前beanName放入targetSourcedBeans缓存中,直接走创建代理的分支        //不会走createBean去创建Bean,这里就是给一个机会。        //关于自定义TargetSource这个分支暂时不讲。        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);                //一般情况下targetSource为null不会走这个分支 直接返回null        //一般情况下targetSource为null不会走这个分支 直接返回null        //一般情况下targetSource为null不会走这个分支 直接返回null        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;   }

if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) 这行代码就是判断我们这个业务类是否需要被代理,进入isInfrastructureClass代码:

java //判断Advice、Pointcut、Advisor、AopInfrastructureBean //是否是我们的beanClass的超类或者超接口 protected boolean isInfrastructureClass(Class<?> beanClass) {        return (super.isInfrastructureClass(beanClass) ||               (this.aspectJAdvisorFactory != null &&                      this.aspectJAdvisorFactory.isAspect(beanClass)));   }

调用父类的方法

java protected boolean isInfrastructureClass(Class<?> beanClass) {   //判断Advice、Pointcut、Advisor、AopInfrastructureBean   //是否是beanClass的超类或者超接口        boolean retVal = Advice.class.isAssignableFrom(beanClass) ||                Pointcut.class.isAssignableFrom(beanClass) ||                Advisor.class.isAssignableFrom(beanClass) ||                AopInfrastructureBean.class.isAssignableFrom(beanClass);                return retVal;   }

首先会调用父类的方法 class1.isAssignableFrom(class2) 判定此 Class1 对象所表示的类或接口与指定的 Class2 参数所表示的类或接口是否相同,或是否是其超类或超接口。

如果是则返回 true;否则返回 false。

Advice、Pointcut、Advisor等是跟切面相关的,不需要代理。 如果父类方法返回false,继续判断该类是不是一个切面,是切面的话也是不需要被代理的。

shouldSkip(beanClass, beanName)是判断beanName不为空且不是original instance。

如果2个条件都是false才会被代理 符合条件的放入advisedBeans 集合中,后面会根据这个集合判断业务类是否需要被代理。

上面只是判断是否需要代理。如果是不需要代理的class加入不需要代理的Map集合中。

TargetSource targetSource = getCustomTargetSource(beanClass, beanName);

getCustomTargetSource(beanClass, beanName);一般情况下targetSource为null

targetSource为null直接返回null的话就不会提前创建代理了。也就是说getCustomTargetSource方法如果返回TargetSource类型,那么if逻辑里会将当前bean加入this.targetSourcedBeans.add(beanName);并且为当前类生成代理,那么getCustomTargetSource方法逻辑是什么呢?我们进去看看

```java @Nullable protected TargetSource getCustomTargetSource(Class> beanClass, String beanName) {

if (this.customTargetSourceCreators != null && this.beanFactory != null && this.beanFactory.containsBean(beanName)) { for (TargetSourceCreator tsc : this.customTargetSourceCreators) { TargetSource ts = tsc.getTargetSource(beanClass, beanName); if (ts != null) { // Found a matching TargetSource. if (logger.isTraceEnabled()) { logger.trace("TargetSourceCreator [" + tsc + "] found custom TargetSource for bean with name '" + beanName + "'"); } return ts; } } }

// No custom TargetSource found. return null; } ```

先看第一个判断this.customTargetSourceCreators != null,首先要知道this是谁?

this是AbstractAutoProxyCreator,customTargetSourceCreators是他的属性

AbstractAutoProxyCreator暴露了一个方法

setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators)

总结一下:那也就是说如果我们想要在bean实例化之前,就为类生成代理。我们需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。

继续往下看

如果customTargetSourceCreators成员有值,于是遍历该成员。

调用TargetSourceCreator#getTargetSource方法,方法逻辑如下

```java @Override @Nullable public final TargetSource getTargetSource(Class> beanClass, String beanName) { //此处是模板模式会调用到AbstractBeanFactoryBasedTargetSourceCreator的具体子类方法中, //具体子类方法会返回TargetSource AbstractBeanFactoryBasedTargetSource targetSource = createBeanFactoryBasedTargetSource(beanClass, beanName); if (targetSource == null) { return null; }

if (logger.isDebugEnabled()) { logger.debug("Configuring AbstractBeanFactoryBasedTargetSource: " + targetSource); }

//拷贝1个新的internalBeanFactory DefaultListableBeanFactory internalBeanFactory = getInternalBeanFactoryForBean(beanName);

// We need to override just this bean definition, as it may reference other beans // and we're happy to take the parent's definition for those. // Always use prototype scope if demanded. BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName); GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd); if (isPrototypeBased()) { bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE); } internalBeanFactory.registerBeanDefinition(beanName, bdCopy);

// Complete configuring the PrototypeTargetSource. targetSource.setTargetBeanName(beanName); //设置拷贝的internalBeanFactory到targetSource targetSource.setBeanFactory(internalBeanFactory);

return targetSource; } ```

AbstractBeanFactoryBasedTargetSourceCreator类是TargetSourceCreator接口的一个抽象实现类。 createBeanFactoryBasedTargetSource(beanClass, beanName);是标准的模板模式。

createBeanFactoryBasedTargetSource(beanClass, beanName);会调用到AbstractBeanFactoryBasedTargetSourceCreator的具体子类方法中,返回TargetSource。

接着往下看getInternalBeanFactoryForBean(beanName);创建一个新的BeanFactory,新的BeanFactory会拥有老的BeanFactory的属性。但需要注意的是,新BeanFactory的BeanPostProcessor集合里,去除了AbstractAutoProxyCreator类型,如下

java protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) { synchronized (this.internalBeanFactories) { DefaultListableBeanFactory internalBeanFactory=this.internalBeanFactories.get(beanName); if (internalBeanFactory == null) { internalBeanFactory = buildInternalBeanFactory(this.beanFactory); this.internalBeanFactories.put(beanName, internalBeanFactory); } return internalBeanFactory; } }

```java protected DefaultListableBeanFactory buildInternalBeanFactory(ConfigurableBeanFactory containingFactory) { // Set parent so that references (up container hierarchies) are correctly resolved. DefaultListableBeanFactory internalBeanFactory = new DefaultListableBeanFactory(containingFactory);

// 拷贝所有的BeanPostProcessor internalBeanFactory.copyConfigurationFrom(containingFactory);

//排除了AOP核心组件对应的BeanPostProcessor internalBeanFactory.getBeanPostProcessors().removeIf(beanPostProcessor -> beanPostProcessor instanceof AopInfrastructureBean);

return internalBeanFactory; } ```

我们可以看到是克隆一个原来的BeanFactory出来,然后将里面所有的AopInfrastructureBean组件都进行移除,而这个组件是什么?其实就是我们的AOP的核心组件,相当于就是将克隆出来的BeanFactory当中的所有AOP的组件全部remove掉。

参考链接:https://ac.nowcoder.com/discuss/826829?type=1&order=3&pos=26&page=1

到此,类的代理对象就生成了,克隆出来的BeanFactory当中的所有AOP的组件被全部remove掉。所以之后的spring的实例化逻辑也不会生成代理了。

总结一下:如果我们想要在bean实例化之前,就为类生成代理,需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类。

调用代理对象方法

假设生成的是jdk代理。当调用对象方法时,会进入invoke方法。方法首先获取TargetSource对象

```java @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;
   //调用getTarget获取原来的对象
   target = targetSource.getTarget();

}

```

调用targetSource.getTarget();获取原来的对象.

在前言里提到的aop流程中,最终生成的TargetSource是SingletonTargetSource类型,于是获取到的target就是原来的对象。

而在上述流程中,我们是提前生成代理的,生成的TargetSource类型是我们钩子方法里自定义的,所以获取到的target取决于我们如何实现。

总结一下:如果我们想要在bean实例化之前,就为类生成代理,还需要提供TargetSource接口的实现。

下面我们自己来实现TargetSource相关接口。

使用TargetSource提前创建代理

日志接口

```java package target.source;

import org.springframework.stereotype.Component;

@Component public interface LogService {

void print();

} ```

日志接口实现类

```java package target.source;

import org.springframework.stereotype.Component;

@Component public class AopLog implements LogService {

public String log() { System.out.println("----log----"); return "log"; }

@Override public void print() { System.out.println("----print----"); } } ```

配置类

```java package target.source;

import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy(proxyTargetClass = false) @ComponentScan() public class BeanConfig {

} ```

切面和切面表达式

```java package target.source;

import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.core.PriorityOrdered; import org.springframework.stereotype.Component;

@Aspect @Component public class Aop implements PriorityOrdered {

//指定切入点表达式,拦截那些方法,即为那些类生成代理对象
//@Pointcut("execution(* com.bie.aop.UserDao.save(..))")  ..代表所有参数
//@Pointcut("execution(* com.bie.aop.UserDao.*())")  指定所有的方法
//@Pointcut("execution(* com.bie.aop.UserDao.save())") 指定save方法

@Pointcut("execution(* aop.*.*(..))")
public void pointCut(){

}

@Before("pointCut()")
public void Before(){
    System.out.println("Before");
}

@After("pointCut()")
public void After(){
    System.out.println("After");
}

@AfterThrowing("pointCut()")

public void AfterThrowing(){ System.out.println("AfterThrowing"); }

@AfterReturning("pointCut()") public void AfterReturning(){ System.out.println("AfterReturning"); }

@Around("pointCut()") public void Around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Around Before"); joinPoint.proceed(); System.out.println("Around After"); }

@Override public int getOrder() { return 1; } } ```

根据上面的总结:如果我们想要在bean实例化之前,就为类生成代理:

1.需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类

2.需要提供TargetSource接口的实现。

3.需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。

下面就是开始做这些事情。

CustomTargetSourceCreator

1.需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类

```java package target.source;

import org.springframework.aop.framework.autoproxy.target.AbstractBeanFactoryBasedTargetSourceCreator; import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class CustomTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {

@Override
protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(Class<?> beanClass, String beanName) {
    if (getBeanFactory() instanceof ConfigurableListableBeanFactory) {
        if(beanClass.isAssignableFrom(AopLog.class)) {
            return new CustomTargetSource();
        }
    }
    return null;
}

} ```

CustomTargetSource

2.需要提供TargetSource接口的实现。

```java package target.source;

import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;

import java.io.Serializable;

public class CustomTargetSource extends AbstractBeanFactoryBasedTargetSource implements Serializable { private static final long serialVersionUID = 5177019431887513952L;

@Override
public Object getTarget() throws Exception {
    //此处获取的BeanFactory是上面拷贝出来的BeanFactory
    return getBeanFactory().getBean(getTargetBeanName());
}

} ```

其中getBeanFactory()的值,是上述流程提到的新的BeanFactory。

由于该BeanFactory的BeanPostProcessor没有了AbstractAutoProxyCreator。

所以getBeanFactory().getBean(getTargetBeanName())获取的bean,一定是原生的bean,而不是代理对象。

CustomTargetSourceCreatorBeanPostProcessor

3.需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。

```java package target.source;

import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.PriorityOrdered; import org.springframework.stereotype.Component;

@Component public class CustomTargetSourceCreatorBeanPostProcessor implements BeanPostProcessor, PriorityOrdered, BeanFactoryAware {

private BeanFactory beanFactory;

@Override
public int getOrder() {
    return 45;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if(bean instanceof AnnotationAwareAspectJAutoProxyCreator) {
        AnnotationAwareAspectJAutoProxyCreator creator 
                        = (AnnotationAwareAspectJAutoProxyCreator)bean;
        CustomTargetSourceCreator targetSourceCreator
                        = new CustomTargetSourceCreator();
         targetSourceCreator.setBeanFactory(beanFactory);
         creator.setCustomTargetSourceCreators(targetSourceCreator);
    }
    return bean;
}

//这里的BeanFactory是原生的BeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    this.beanFactory = beanFactory;
}

} ```

光写了CustomTargetSourceCreator 还不行,因为它必须作为AbstractAutoProxyCreator类的成员,所以我们需要给AbstractAutoProxyCreator的成员赋值。

此处我们自定义了CustomTargetSourceCreatorBeanPostProcessor。

到此,我们就完成了对StudentServiceImpl类型提前生成代理功能的整合。

参考链接:https://blog.csdn.net/qq_39002724/article/details/112970421

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
org.aopalliance.aop是一个Java领域的开源项目,是AspectJ和其他AOP框架之间的一个接口标准化项目。AOP(面向切面编程)是一种编程范式,它允许开发人员将通用的业务逻辑与应用程序的特定功能进行分离,从而提高代码的可重用性和可维护性。 org.aopalliance.aop项目的主要目的是定义一组接口,用于描述AOP框架的核心概念,例如切面(Aspect)、连接点(Join point)和通知(Advice)等。这些接口提供了一种标准的方式来表示和操作切面逻辑,从而使不同的AOP框架之间能够互相兼容。 要下载org.aopalliance.aop项目,可以访问其官方网站或开源代码托管平台,如GitHub等。从官方网站下载通常会提供编译好的二进制文件(JAR包)以及相关的文档。如果需要查看或参与开发,也可以访问项目的代码托管平台获取源代码。 下载org.aopalliance.aop项目后,可以将其导入Java开发环境,并添加到自己的项目依赖中。通过使用org.aopalliance.aop提供的接口,开发人员可以轻松地定义和应用切面逻辑,以实现应用程序中的横切关注点(cross-cutting concerns)。这样可以大大简化代码,提高系统的灵活性和可重用性。 总之,org.aopalliance.aop项目是一个重要的AOP接口标准化项目,通过定义一组接口,实现不同AOP框架之间的兼容性,从而帮助开发人员更加方便地使用AOP编程范式,提高代码质量和开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值