Spring驱动注解②

该文档是:Spring加深理解...

博客连接:https://www.loveuluo.cn

日期:2021-01-21

1. AOP功能测试

1.1 AOP扩展:JoinPoint 对象

JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
常用api:

方法名功能
Signature getSignature();获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs();获取传入目标方法的参数对象
Object getTarget();获取被代理的对象
Object getThis();获取代理对象

ProceedingJoinPoint对象:

ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中,
添加了
Object proceed() throws Throwable //执行目标方法
Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法
两个方法.

1.2 AOP测试

指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式(动态代理)

细节流程

1、导入aop模块; Spring AOP:(spring-aspects)

2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法运行之前、方法运行结束、方法出现异常…等)

3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div方法运行到哪里了然后执行对应的方法

通知方法:
        前置通知(@Before):logStart ---目标方法运行(div)运行之前执行
        后置通知(@After):logEnd --- 目标方法运行(div)运行之后执行(无论方法正常结束还是异常结束,都会执行)
        返回通知(@AfterReturning):logReturn --- 目标方法运行(div)正常返回之后执行
        异常通知(@AfterThrowing):logException --- 目标方法运行(div)出现异常后执行
        环绕通知(@Around):动态代理,手动推荐目标方法运行(joinPoint.procced())

4、给切面类的目标方法标注何时何地运行

5、将切面类和业务逻辑类(目标方法所在的类) 都加入到IOC容器中

6、必须告诉Spring哪个类是切面类,给切面类上加上 @Aspect

7、给配置类中标注 @EnableAspectJAutoProxy 开启基于注解的AOP模式 【最关键的一步】
在Spring中很多的@EnableXXX; 都是开启某一项功能

总结三步流程:

1、将业务逻辑组件切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect

2、在切面类上的每个通知方法上标注通知注解,告诉spring何时何地运行(切入点表达式)

3、开启基于注解的AOP模式 给配置类中标注 (@EnableAspectJAutoProxy

实现功能:

配置类:

@EnableAspectJAutoProxy//开启基于注解的AOP模式 必须要有
@Configuration
public class MainConfigOfAOP {

    //业务逻辑类加入容器中
    @Bean
    public MathCalculator calculator(){
        return new MathCalculator();
    }

    //切面类加入到容器中
    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}

切面类:

/**
 * 切面类
 * @Aspect: 告诉Spring当前类是一个切面类
 */
@Aspect
public class LogAspects {

    //抽取公共的切入点表达式
    //1、本类引用
    //2、其他的切面引用
    @Pointcut("execution(public int com.Luo.aop.MathCalculator.*(..))")
    public void pointCut(){};

    //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
    @Before("pointCut()")
    //JoinPoint一定要出现在参数表的第一位
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
    }

    @After("com.Luo.aop.LogAspects.pointCut()")//如果是别的类要引用当前类的公共切入点表达式,可以写上全类名
    public void logEnd(JoinPoint joinPoint){
        System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
    }

    //JoinPoint一定要出现在参数表的第一位 returning是指定返回的参数
    @AfterReturning(value="pointCut()",returning="result")
    public void logReturn(JoinPoint joinPoint,Object result){
        System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
    }

    //throwing="exception" 告诉Spring这是用来接收异常的,不然它也不知道这是干啥用的
    @AfterThrowing(value="pointCut()",throwing="exception")
    public void logException(JoinPoint joinPoint,Exception exception){
        System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
    }

}

业务逻辑类:

public class MathCalculator {
    public int div(int i,int j){
        System.out.println("MathCalculator...div...");
        return i/j;
    }
}

测试类:

    @Test
    public void test01(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
        //1、不要自己创建对象
//    MathCalculator mathCalculator = new MathCalculator();
//    mathCalculator.div(1, 1);
        MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
        mathCalculator.div(1, 1);
        applicationContext.close();
    }

测试结果:

  • 没出错的情况

image-20210121192122969

  • 出现异常的情况

image-20210121192150166

2. AOP原理

AOP原理:【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】

2.1 @EnableAspectJAutoProxy

1、@EnableAspectJAutoProxy是什么?
@Import(AspectJAutoProxyRegistrar.class):给容器中导入AspectJAutoProxyRegistrar
利用AspectJAutoProxyRegistrar(实现了ImportBeanDefinitionRegistrar接口)自定义给容器中注册bean:
给容器中注册的就是=》internalAutoProxyCreator(这是id)=AnnotationAwareAspectJAutoProxyCreator(这是类型)

2、 AnnotationAwareAspectJAutoProxyCreator(它相当于是一个后置处理器也是一个Aware接口的实现类):AnnotationAwareAspectJAutoProxyCreator
继承了 ->AspectJAwareAdvisorAutoProxyCreator
继承了 ->AbstractAdvisorAutoProxyCreator
继承了 ->AbstractAutoProxyCreator
实现了 ->SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

2.2 AnnotationAwareAspectJAutoProxyCreator分析

主要分析它作为后置处理器(在bean初始化完成前后做事情)、作为BeanFactoryAware又做了哪些工作!

找到和我们特性有关的方法:
AbstractAutoProxyCreator.setBeanFactory()
AbstractAutoProxyCreator类中有后置处理器的逻辑;
AbstractAdvisorAutoProxyCreator.setBeanFactory()[子类重写了这个方法]-》这个方法里调用了initBeanFactory()方法
AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()这个类又重写了上边的initBeanFactory()方法

2.3 注册AnnotationAwareAspectJAutoProxyCreator流程.

创建和注册AnnotationAwareAspectJAutoProxyCreator的过程

流程:
1、传入配置类,创建ioc容器
2、注册配置类,调用refresh(),刷新容器
3、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建
    1)、先获取ioc容器中已经定义了的需要创建对象的所有BeanPostProcessor
    2)、给容器中加别的BeanPostProcessor
    3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor
    4)、再给容器中注册实现了Ordered接口的BeanPostProcessor
    5)、注册没实现优先级接口的BeanPostProcessors
    6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中
        创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
        1)、创建Bean的实例
        2)、populateBean;给bean的各种属性赋值
        3)、initializeBean:初始化bean
            1、invokeAwareMethods():处理Aware接口的方法回调
            2、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
            3、invokeAwareMethods():执行指导员的初始化方法
            4、applyBeanPostProcessorsAfterInitialization():应用后置处理器的postProcessAfterInitialization()
        4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;---> BeanFactoryAspectJAdvisorsBuilderAdapter
    7)、把BeanPostProcessor注册到BeanFactory中:
    beanFactory.addBeanPostProcessor(postProcessor)

2.4 AnnotationAwareAspectJAutoProxyCreator执行时机

AnnotationAwareAspectJAutoProxyCreator ===> postProcessBeforeInstantiation

4、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作,创建剩下的单实例bean
    1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
    getBean ---> doGetBean() ---> getSingleton()
    2)、创建bean
    【AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用】
        1、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的;直接使用,否则再创建
            只要创建好的bean都会被缓存起来
        2、createBean();创建bean;AnnotationAwareAspectJAutoProxyCreator会在任何bean创建之前先尝试返回bean的实例
            【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】
            【InstantiationAwareBeanPostProcessor是在创建bean实例之前先尝试用后置处理器返回对象】
            1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation
                希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续接下来
                1)、后置处理器先尝试返回对象
                        bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                            拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;
                            就执行postProcessBeforeInstantiation()
            2)、doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例;和上面3.6流程一样

2.5 创建AOP代理

AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】的作用:

1、每个bean创建之前,调用postProcessBeforeInstantiation()
    关心 MathCalculator和LogAspects的创建
    1)、判断当前bean是否在advisedBeans中(保存了所有需要增强的bean(需要加入额外功能的bean))
    2)、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean
    或者是否是切面(@Aspect)
    3)、是否需要跳过
        1、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】
        每一个封装的通知方法的增强器是InstantiationModeAwarePointcutAdvisor
        判断每一个增强器是否是AspectJPointcutAdvisor类型的,返回为true
        2、永远返回false
2、创建对象
postProcessorAfterInitialization;
return wrapIfNecessary(bean,beanName,cacheKey);包装 如果需要的情况下
    1)、获取当前bean的所有增强器(通知方法) Object[] specificInterceptors
        1、找到候选的所有增强器(找哪些通知方法是需要切入bean方法的)
        2、获取到能在当前bean使用的增强器
        3、给增强器排序
    2)、保存当前bean在advisedBeans中:
    3)、如果当前bean需要增强,创建当前bean的代理对象
        1、获取所有增强器(通知方法)
        2、保存了proxyFactory
        3、创建代理对象:Spring自动决定
        JdkDynamicAopProxy(config);jdk的动态代理
        ObjenesisCglibAopProxy(config);cglib的动态代理
    4)、给容器中返回当前组件使用cglib增强了的代理对象;
    5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程

2.6 获取拦截链-MethodInterceptor

3、目标方法执行
容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(如所有的增强器,目标对象,XXX。。。)
    1)、CglibAopProxy.intercept();拦截目标方法的执行
    2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链:
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        [1]、List<Object> interceptorList保存所有拦截器 5个
        一个默认的ExposeInvocationInterceptor 和 4个增强器
        [2]、遍历所有的增强器,将其转为Interceptor:
        registry.getInterceptors(advisor);
        [3]、将增强器转为List<MethodInterceptor>;
        如果是MethodInterceptor,直接加入到集合中
        如果不是MethodInterceptor,使用AdvisorAdapter将增强器转为MethodInterceptor
        转换完成,返回MethodInterceptor数组

    3)、如果没有拦截器链,直接执行目标方法
    拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
    4)、如果有拦截器链,把需要执行的目标对象、目标方法、拦截器链等所有信息传入创建一个CglibMethodInvocation对象并调用proceed()方法:
    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

2.7 链式调用通知方法

5)拦截器链的触发过程
    1、如果没有拦截器执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
    2、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
    拦截器链机制,保证通知方法与目标方法的执行顺序

image-20210121210420137

2.8 AOP原理总结

1、@EnableAspectJAutoProxy 开启AOP功能
2、@EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
3、AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器
4、容器的创建流程:
    1)、registerBeanPostProcessors() 注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator的对象
    2)、finishBeanFactoryInitialization() 初始化剩下的单实例bean
        1、创建业务逻辑组件 和 切面组件
        2、AnnotationAwareAspectJAutoProxyCreator后置处理器会拦截组件创建的过程
        3、组件创建完后,判断组件是否需要增强(添加被的功能)
        是,切面里面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib)
5、执行目标方法:
    1)、代理对象执行目标方法
    2)、通过CglibAopProxy.intercept()进行拦截
        1、得到目标方法的拦截器链(增强器包装成拦截器_MethodInterceptor)
        2、利用拦截器链式机制,依次进入每一个拦截器进行执行
        3、效果:
        正常执行: 前置通知--目标方法--后置通知--返回通知
        出现异常: 前置通知--目标方法--后置通知--异常通知

3. 声明式事务

3.1 环境搭建

导入依赖:

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.44</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>

配置文件:

db.user=root
db.password=123456
db.driverClass=com.mysql.jdbc.Driver

配置类:

@PropertySource("classpath:/dbconfig.properties")
@Configuration
@ComponentScan("com.Luo.tx")
public class TxConfig {

    @Value("${db.user}")
    private String user;
    @Value("${db.password}")
    private String pwd;
    @Value("${db.driverClass}")
    private String driverClass;

    //数据源
    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Bean
    //@Bean标注的方法创建对象的时候,方法参数的值从容器中获取:
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        //直接传入从容器中获取的dataSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        
        //也可以使用这种调用方法的做法
        //Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
        //JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        
        return jdbcTemplate;
    }

}

dao类:

@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public void insert(){
        String sql ="INSERT INTO tbl_user(username,age) VALUES(?,?)";
        String username = UUID.randomUUID().toString().substring(0, 5);
        jdbcTemplate.update(sql,username,20);
    }
}

Service类:

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    
    public void insertUser(){
        userDao.insert();
        int i = 10 / 0; //出现异常后 方法不会回滚
        System.out.println("插入成功...");
    }

}

测试类:

public class IOCTest_tx {
    @Test
    public void test01(){
        //创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = applicationContext.getBean(UserService.class);
        userService.insertUser();
    } 
}

3.2 使用事务

在配置类上标注@EnableTransactionManagement

@EnableTransactionManagement
public class TxConfig {}

给需要加事务的方法标注@Transactional

@Transactional
public void insertUser(){
    userDao.insert();
    int i = 10 / 1;
    System.out.println("插入成功");
}

在配置类中,配置事务管理器,来控制事务:

//注册事务管理器在容器中
@Bean //@Bean标注的方法创建对象的时候,方法参数的值从容器中获取:
public PlatformTransactionManager transactionManager(DataSource dataSource){
    return new DataSourceTransactionManager(dataSource);//要加入数据源,控制数据源
}

总结:

1、开启事务管理功能 标注@EnableTransactionManagement
2、给需要加事务的方法上标注@Transactional
3、在配置类中,配置事务管理器,来控制事务

3.3 源码分析

事务管理通过AOP机制实现。

   1、@EnableTransactionManagement
       利用 TransactionManagementConfigurationSelector 给容器中导入组件
       导入两个组件:
           AutoProxyRegistrar
           ProxyTransactionManagementConfiguration

   2、AutoProxyRegistrar:
           给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件
           InfrastructureAdvisorAutoProxyCreator: ?
               利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;

   3、ProxyTransactionManagementConfiguration
           1)、给容器中注册 事务增强器
                   ①事务增强器要用事务注解的信息
                       AnnotationTransactionAttributeSource 解析事务注解
                   ②事务拦截器:
                       TransactionInterceptor 保存了事务的属性信息,事务管理器
                       他是一个MethodInterceptor
                       在目标方法执行的时候:
                           执行拦截器链;
                           事务拦截器TransactionInterceptor
                               1、先获取事务相关的属性
                               2、再获取PlatformTransactionManager事务管理器;
                                   如果事先没有添加指定任何TransactionManager
                                   最终会从容器中按照类型获取一个PlatformTransactionManager
                               3、执行目标方法:
                                   如果异常,获取到事务管理器,利用事务管理器回滚这次操作
                                   如果正常,利用事务管理器,提交事务

总结:

通过@EnableTransactionManagement注解会为容器中导入AutoProxyRegistrarProxyTransactionManagementConfiguration两个组件;

AutoProxyRegistrar会给容器再注册InfrastructureAdvisorAutoProxyCreator组件,利用后置处理器在对象创建以后,将包装对象,并返回一个代理对象(增强器),返回的代理对象执行方法利用拦截器链调用

ProxyTransactionManagementConfiguration会给容器中注册事务增强器,并给其获取解析事务注解的信息;同时也用事务拦截器先获取事务相关属性,再获取PlatformTransactionManager事务管理器,再执行目标方法,如果异常就回滚操作正常则利用事务管理器提交事务

4. 扩展原理

4.1 BeanFactoryPostProcessor

BeanPostProcessor是bean的后置处理器,BeanFactoryPostProcessor是创建bean的工厂的后置处理器。

  • BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作。
  • BeanFactoryPostProcessor:beanFactory的后置处理器。

执行时机

  • BeanFactoryPostProcessor执行时机:所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建。

原理流程

  • 1)、ioc容器创建对象
  • 2)、invokeBeanFactoryPostProcessors(beanFactory)方法执行(在创建容器的refresh()方法中执行的);

    • image-20210122134349311
    • 如何找到所有的BeanFactoryPostProcessor并执行他们的方法?
    • 2.1)、直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法
    • 2.2)、在初始化创建其他组件前面执行

代码测试:

测试用的Bean实体类:

public class Blue {
    public Blue() {
        System.out.println("blue...无参构造执行...");
    }
}

自定义BeanFactoryPostProcessor:

@Component //比如加入Spring容器中才能生效
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        //执行时机:这时候所有的bean都还没创建,只是定义了
        System.out.println("MyBeanFactoryPostProcessor。。。postProcessBeanFactory执行。。。");
        //可以拿到有几个bean定义了
        int beanCount = beanFactory.getBeanDefinitionCount();
        //可以拿到每个bean的名字
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();

        System.out.println("当前BeanFactory有【 " + beanCount+" 】个Bean");
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println("容器中已经定义的bean:"+beanDefinitionName);
        }
    }
}

配置类:

@ComponentScan("com.Luo.ext")
@Configuration
public class ExtConfig {
    @Bean
    public Blue blue(){
        return new Blue();
    }
}

测试代码:

public class IOCTest_Ext {
    @Test
    public void test01(){
        //创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
    }
}

测试结果:

image-20210122135016442

4.2 BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的子接口。

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {}
  • postProcessBeanDefinitionRegistry()方法是BeanDefinitionRegistryPostProcessor接口中的方法。

执行时机

  • 在所有bean定义信息将要被加载,bean实例还未被创建的时候。
  • 也就是说BeanDefinitionRegistryPostProcessor优先于BeanFactoryPostProcessor执行;

可以利用BeanDefinitionRegistryPostProcessor再给容器中额外添加组件。

原理流程

  • 1、创建ioc容器
  • 2、创建容器的refresh()方法执行 ---》refresh()中的其中一个方法invokeBeanFactoryPostProcessors(beanFactory);
  • 3、先从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件,

    • 3.1、依次触发所有的postProcessBeanDefinitionRegistry()方法
    • 3.2、再来触发postProcessBeanFactory()方法
  • 4、再来从容器中找到BeanFactoryPostProcessor组件,然后依次postProcessBeanFactory()方法

代码测试:

自定义BeanDefinitionRegistryPostProcessor

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    //BeanDefinitionRegistry是Bean定义信息的保存中心,BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息来创建bean实例的
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("MyBeanDefinitionRegistryPostProcessor执行=》bean数量:【 " + registry.getBeanDefinitionCount() +" 】");
        //容器中添加组件方式一:
//      RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);

        //容器中添加组件方式二:
        System.out.println("MyBeanDefinitionRegistryPostProcessor=》添加一个组件进入容器!");
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Blue.class).getBeanDefinition();
        registry.registerBeanDefinition("tianjiadezujian",beanDefinition);
    }


    //因为BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口,所以也需要实现postProcessBeanFactory()方法
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("postProcessBeanFactory执行=》bean数量:【 " + beanFactory.getBeanDefinitionCount() +" 】");
    }
}

配置类:

@ComponentScan("com.Luo.ext")
@Configuration
public class ExtConfig {

    @Bean
    public Blue blue(){
        return new Blue();
    }

}

测试类:

public class IOCTest_Ext {
    @Test
    public void test01(){
        //创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
    }
}

测试结果:

image-20210122142015889

4.3 ApplicationListener用法

ApplicationListener: 监听容器中发布的事件。事件驱动模型开发

  • 监听ApplicationEvent及其子事件
public interface ApplicationListener<E extends ApplicationEvent>

步骤

  • 1、写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子事件)
  • 2、把监听器加入到ioc容器中
  • 3、只要容器中有相关事件的发布,我们就能监听到这个事件

    • ContextRefreshedEvent: 容器刷新完成(所有bean都完全创建)会发布这个事件
    • ContextClosedEvent: 关闭容器会发布这个事件
  • 4、自己发布一个事件 : applicationContext.publishEvent()

代码测试:

自定义监听器:

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
    //当容器中发布此事件以后,方法会得到触发
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("收到事件: "+ event);
    }
}

配置类:

@ComponentScan("com.Luo.ext")
@Configuration
public class ExtConfig {
}

测试类:

public class IOCTest_Ext {
    @Test
    public void test01(){
        //创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
        //简单自定义发布事件(匿名内部类)
        applicationContext.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
        });
        //关闭容器
        applicationContext.close();
    }
}

测试结果:

image-20210122144415617

4.4 ApplicationListener原理&事件发布原理

当前事件: ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的事件]、ContextClosedEvent

当前三个事件的ApplicationListener原理:

  • 1、ContextRefreshedEvent事件:

    • 1.1)、容器创建对象:refresh();
    • 2.1)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
  • 2、自己发布事件
  • 3、容器关闭会发布 publishEvent(new ContextClosedEvent(this));

事件发布流程:每个事件发布流程都一样

publishEvent(new ContextRefreshedEvent(this));
    1、获取事件的多播器(派发器):getApplicationEventMulticaster()
    2、multicastEvent(applicationEvent, eventType); 派发事件
    3、获取到所有的ApplicationListener;
            for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {}
        3.1)、如果有Executor,可以支持使用Executor进行异步派发
            Executor executor = getTaskExecutor();
        3.2)、否则,同步的方式直接执行listener方法;
            invokeListener(listener, event);
            拿到listener回调onApplicationEvent()方法;

事件多播器(派发器)

 【事件多播器(派发器)】
       1、容器创建对象:refresh();
       2、initApplicationEventMulticaster();初始化ApplicationEventMulticaster;
           1)、先去容器找有没有id="applicationEventMulticaster"的组件;
               如果有: beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
               如果没有: new SimpleApplicationEventMulticaster(beanFactory)
               并且加入到容器中 beanFactory.registerSingleton,就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster

容器中有哪些监听器

 【容器中有哪些监听器】
       1、容器创建对象:refresh();
       2、registerListeners();
           从容器中拿到所有的监听器:
           String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);

           把拿到的listener注册到applicationEventMulticaster中:
           getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

4.5 @EventListenerSmartInitializingSingleton

可通过@EventListener注解 来将方法标注成监听方法

原理: 使用 EventListenerMethodProcessor 处理器来解析方法上的 @EventListener注解

EventListenerMethodProcessorSmartInitializingSingleton的实现类

public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware {}

EventListenerMethodProcessor将该方法对象,转成监听器对象

@Service
public class UserService {
    //通过@EventListener来将listener方法,标注成监听方法
    @EventListener(classes = ApplicationEvent.class)
    public void listener(ApplicationEvent event){
        System.out.println("UserService监听到的事件: " + event);
    }
}

SmartInitializingSingleton原理

判断是否是SmartInitializingSingleton类型,如果是就调用smartSingleton.afterSingletonsInstantiated();

SmartInitializingSingleton原理: -->  afterSingletonsInstantiated();
1、ioc容器创建对象并 refresh();
2、    finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean
    1)、先创建所有单实例bean;getBean(beanName);
    2)、获取所有创建好的单实例bean,判断是否是 SmartInitializingSingleton类型;
    如果是,就调用smartSingleton.afterSingletonsInstantiated();

5. Spring容器创建原理

spring核心逻辑AbstractApplicationContextrefresh()方法如下

public void refresh() {
    synchronized (this.startupShutdownMonitor) {
        // 刷新前的预准备工作
        prepareRefresh();
        // 提取bean的配置信息并封装成BeanDefinition实例,然后将其添加到注册中心。注册中心是一个ConcurrentHashMap<String,BeanDefinition>类型,key为Bean的名字,value为BeanDefinition实例。
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
       //对beanFactory进行一些配置,注册一些BeanPostProcessor和一些特殊的Bean。
        prepareBeanFactory(beanFactory);
        
            //留给子类在BeanFactory准备工作完成后处理一些工作。
            postProcessBeanFactory(beanFactory);
           //调用 BeanFactory的后置处理器。
           invokeBeanFactoryPostProcessors(beanFactory);
           //注册Bean的后置处理器。
            registerBeanPostProcessors(beanFactory);
            //国际化相关功能
            initMessageSource();
            //初始化事件派发器;
            initApplicationEventMulticaster();
            // 提供给子容器类,供子容器去实例化其他的特殊的Bean
            onRefresh();
            // 处理容器中已有的ApplicationListener
            registerListeners();
            //初始化容器中剩余的单实例bean
            finishBeanFactoryInitialization(beanFactory);
            //最后一步
            finishRefresh();
        
        }
    }

5.1 BeanFactory预准备

Spring容器的refresh()【创建刷新】;
1、prepareRefresh();刷新前的预处理
    1)、initPropertySources();初始化一些属性设置;子类自定义个性化属性设置方法
    2)、getEnvironment().validateRequiredProperties();检验属性的合法性
    3)、this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();保存容器中的一些早期事件
2、obtainFreshBeanFactory();获取BeanFactory
    1)、refreshBeanFactory();刷新【创建】BeanFactory
            创建了一个this.beanFactory = new DefaultListableBeanFactory();
            设置id
    2)、getBeanFactory();返回刚才GenericApplicationContext创建的BeanFactory对象
    3)、将创建的BeanFactory【DefaultListableBeanFactory】返回;
3、prepareBeanFactory(beanFactory);BeanFactory预准备工作(BeanFactory进行一些设置)
    1)、设置BeanFactory的类加载器、支持表达式解析器...等
    2)、添加部分BeanPostProcessor【ApplicationContextAwareProcessor】
    3)、设置忽略的自动装配的接口EnvironmentAware、EmbeddedValueResolverAware....等
    4)、注册可以解析的自动装配;我们能直接在任何组件中自动注入:
            BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
    5)、添加BeanPostProcessor【ApplicationListenerDetector】
    6)、添加编译时的AspectJ支持:
    7)、给BeanFactory中注册一些能用的组件:
            environment【ConfigurableEnvironment】、
            systemProperties【Map<String, Object>】、
            systemEnvironment【Map<String, Object>】
4、postProcessBeanFactory(beanFactory);BeanFactory准备工作完成后进行的后置处理工作;
    1)、子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步设置

5.2 执行BeanFactoryPostProcessor

5、invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor的方法;
    BeanFactoryPostProcessor:BeanFactory的后置处理器。在BeanFactory标准初始化【前面的预准备过程】之后执行的
    两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
    1)、执行BeanFactoryPostProcessor方法;

        先执行BeanDefinitionRegistryPostProcessor
        1、获取所有BeanDefinitionRegistryPostProcessor;
        2、看先执行实现了PriorityOrdered优先级接口的获取所有BeanDefinitionRegistryPostProcessor
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        3、再执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        4、最后执行没有实现任何优先级或者顺序接口的BeanDefinitionRegistryPostProcessor
            postProcessor.postProcessBeanDefinitionRegistry(registry);

        再执行BeanFactoryPostProcessor的方法
        1、获取所有BeanFactoryPostProcessor;
        2、看先执行实现了PriorityOrdered优先级接口的获取所有BeanFactoryPostProcessor
            postProcessor.postProcessBeanFactory(beanFactory);
        3、再执行实现了Ordered顺序接口的BeanFactoryPostProcessor
            postProcessor.postProcessBeanFactory(beanFactory);
        4、最后执行没有实现任何优先级或者顺序接口的BeanFactoryPostProcessor
            postProcessor.postProcessBeanFactory(beanFactory);

5.3 注册BeanPostProcessor

6、registerBeanPostProcessors(beanFactory);注册BeanPostProcessor(Bean的后置处理器)【intercept bean creation,拦截bean创建过程】
    不同接口类型的BeanPostProcessor,在Bean创建前后的执行时机是不一样的
        BeanPostProcessor、
        DestructionAwareBeanPostProcessor、
        InstantiationAwareBeanPostProcessor、
        SmartInstantiationAwareBeanPostProcessor、
        MergedBeanDefinitionPostProcessor【internalPostProcessors】

    1)、获取所有的BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口指定优先级
    2)、先注册PriorityOrdered优先级接口的BeanPostProcessor
            把每个BeanPostProcessor;添加到BeanFactory中
            beanFactory.addBeanPostProcessor(postProcessor);
    3)、再注册Ordered接口的
    4)、最后注册没有实现任何优先级接口的
    5)、最终注册MergedBeanDefinitionPostProcessor【internalPostProcessors】
    6)、注册一个ApplicationListenerDetector;来在bean创建完成后检查是否是ApplicationListener,
            如果是,applicationContext.addApplicationListener((ApplicationListener<?>) bean);添加到容器中

5.4 初始化MessageSource

7、initMessageSource();初始化MessageSource组件(做国际化功能,消息绑定,消息解析)
    1)、获取BeanFactory
    2)、看容器中是否有id为messageSource的组件,类型为MessageSource的组件
            如果有,赋值给messageSource
            如果没有,自己创建一个DelegatingMessageSource;
                MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
    3)、把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource;
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
        自动注入获取后,调用getMessage();
        MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale);

5.5 初始化事件派发器、监听器等

8、initApplicationEventMulticaster();初始化事件派发器
    1)获取BeanFactory;getBeanFactory();
    2)、从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster
    3)、如果上一步没有自己配置事件派发器;它就创建一个SimpleApplicationEventMulticaster
    4)、将创建的ApplicationEventMulticaster添加到BeanFactory中,以后其他组件直接自动注入

9、onRefresh();留给子容器(子类)
    1)、子类重写这个方法,在容器刷新的时候可以自定义逻辑;

10、registerListeners();给容器中将所有项目里面的ApplicationListener注册进来;
    1)、从容器中拿到所有的ApplicationListener组件
    2)、将每个监听器添加到事件派发器中;
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    3)、派发之前步骤产生的事件

5.6 创建Bean准备&Bean创建完成

11、finishBeanFactoryInitialization(beanFactory);初始化所有剩下的单实例bean
    1)、beanFactory.preInstantiateSingletons();初始化剩下的单实例bean
        1、获取容器中的所有bean,依次进行初始化和创建对象
        2、获取bean的定义信息;RootBeanDefinition
        3、判断Bean不是抽象的,是单实例的,不是懒加载的
            1)、判断是否是FactoryBean;是否是实现FactoryBean接口的Bean;
            2)、不是工厂Bean。利用getBean(beanName);创建对象
                getBean(beanName); ioc.getBean();
                --> doGetBean();
                --> 先获取缓存中保存的单实例Bean。如果能获取到,说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来)
            3)、缓存中拿不到,开始Bean的创建对象流程:
            4)、标记当前bean已经被创建
            5)、获取Bean定义信息;
            6)、【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】
            7)、启动单实例Bean的创建流程;
                1、createBean(beanName,mbd,args);
                2、Object bean = resolverBeforeInstantiation(beanName,mbdToUse);让BeanPostProcessor先拦截返回代理对象
                    【InstantiationAwareBeanPostProcessor】: 提前执行;
                    先触发: postProcessBeforeInstantiation();
                    如果有返回值则,触发,postProcessAfterInstantiation();
                3、如果前面的InstantiationAwareBeanPostProcessor没有返回代理对象;调用4
                4、Object beanInstance = doCreateBean(beanName,mbdToUse,args);;创建bean
                    1)、【创建Bean实例】;createBeanInstance(beanName,mbd,args);
                        利用工厂方法或者对象的构造器创建出Bean实例
                    2)、applyMergedBeanDefinitionPostProcessor(mbd,beanType,beanName);
                        调用MergedBeanDefinitionPostProcessor的bdp.PostProcessMergedBeanDefinition(mbd,beanType,beanName);
                    3)、【为Bean实例属性赋值】populateBean(beanName,mbd,instanceWrapper);
                        赋值之前:
                        1、拿到InstantiationAwareBeanPostProcessor后置处理器;
                            postProcessAfterInstantiation();
                        2、拿到InstantiationAwareBeanPostProcessor后置处理器;
                            postProcessPropertyValues();
                        赋值:
                        3、应用Bean属性的值;为属性利用setter方法等进行赋值;通过反射赋值
                            applyPropertyValues(beanName,mbd,bw,pvs);
                    4)、【Bean初始化】initializeBean(beanName,exposedObject,mbd);
                        1、【执行Aware接口方法】invokeAwareMethods(beanName,bean);执行xxxAware接口的方法
                            BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
                        2、【执行后置处理器初始化之前】applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
                            BeanPostProcessor.postProcessBeforeInitialization();
                        3、【执行初始化方法】invokeInitMethods(beanName,wrappedBean,mbd);
                            1)、是否是InitializingBean接口的实现;执行接口规定的初始化;
                            2)、是否自定义初始化方法
                        4、【执行后置处理器初始化之后】applyBeanPostProcessorsAfterInitialization
                            BeanPostProcessor.postProcessAfterInitialization();
                    5)、注册Bean的销毁方法;

                5、将创建的Bean添加到缓存中singletonObjects;再返回

5.7 容器创建完成后

12、finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成
    1)、initLifecycleProcessor();初始化和生命周期有关的后置处理器;LifecycleProcessor
        默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有就new DefaultLifecycleProcessor();
        加入到容器中;
        写一个LifecycleProcessor的实现类,可以在BeanFactory的onRefresh()、onClose();
    2)、getLifecycleProcessor().onRefresh();
        拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh();
    3)、publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件
    4)、LiveBeansView.registerApplicationContext(this);

5.8 Spring源码总结

1、Spring容器在启动的时候,先会保存所有注册进来的Bean定义信息
    注册Bean的方式:
        1)、xml注册bean:<bean>
        2)、使用注解注册Bean;@Service、@Component、@Bean等.....
2、Spring容器会在何时的时机创建这些Bean
    创建Bean的时机:
        1)、用到这个Bean的时候;利用getBean()创建Bean;创建好后,保存在容器中
        2)、统一创建剩下所有Bean的时候;finishBeanFactoryInitialization(beanFactory)
3、后置处理器:BeanPostProcessor
    1)、每一个bean创建完成,都会使用各种后置处理器进行处理,来增强bean的功能
        如:AutowiredAnnotationBeanPostProcessor:处理自动注入
            AnnotationAwareAspectJAutoProxyCreator:来做AOP功能,给Bean创建代理对象
            AsyncAnnotationBeanPostProcessor:支持异步注解
            .....等
            增强功能注解
4、事件驱动模型:
    ApplicationListener:事件监听
    ApplicationEventMulticaster;事件派发

ioc容器的实质

  • ioc容器就是很多的Map;
  • 很多的Map里面保存了单实例Bean,环境信息等...所有的Map就构成了ioc容器,
  • 获取组件就是从这些Map中拿东
最后修改:2021 年 01 月 22 日 06 : 42 PM
如果觉得我的文章对你有用,请随意赞赏