0
点赞
收藏
分享

微信扫一扫

【尚硅谷】spring注解开发

夏木之下 2022-05-01 阅读 115

文章目录

1、spring注解开发

在这里插入图片描述

2、@Configruation @Bean 给容器中注册组件

1、导入spring依赖包

 <!-- spring 依赖包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.10.RELEASE</version>
</dependency>

在这里插入图片描述

2、以前版本

  • 编写beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="person" class="com.wukong.bean.Person">
        <property name="name" value="张三"/>
        <property name="age" value="18"/>
        <property name="address" value="北京市朝阳区"/>
    </bean>
</beans>
  • 测试
public static void main(String[] args) {
  	//配置文件方式获取ioc容器
    ClassPathXmlApplicationContext context =
            new ClassPathXmlApplicationContext("beans.xml");

    Person person = (Person) context.getBean("person");

    System.out.println(person.toString());
}

3、注解方式

  • Config.java
/配置类  == 配置文件
@Configuration   //告诉spring这是一个配置类
public class MainConfig {

    /**
     * 给容器中注册一个bean类型为返回值类型,id为方法名
     *
     * @return
     */
    @Bean("newPerson")
    public Person person() {
        return new Person("王五", 19, "河北省石家庄市");
    }
}


 //注解方式获取ioc容器
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);

3、@ComponentScan 自动扫描,指定扫描规则

  • 配置版本包扫描
 <context:component-scan base-package="com.wukong.bean"></context:component-scan>-
  • 注解版本

@Controller :扫描控制层(Controller)

@Service :扫描业务层(Service)

@Repository:扫描数据层(DAO)

@Component

在主配置文件需要加上@ComponentScan 指定要扫描的包,上面这些注解才会生效。

  • 详解@ComponentScan 参数

**value( String[ ] ):**指定要扫描哪个包的注解

**useDefaultFilters:**默认为true,如果需要指定过滤规则,则需改成false

**excludeFilters(Filter[ ]):**不需要扫描哪些包

includeFilters( Filter[ ] ):需要扫描哪些的包

  • FIlter【】的参数
public @interface Filter {
    FilterType type() default FilterType.ANNOTATION;  

    @AliasFor("classes")
    Class<?>[] value() default {};

    @AliasFor("value")
    Class<?>[] classes() default {};

    String[] pattern() default {};
}

public enum FilterType {
    ANNOTATION, //按照注解过滤
    ASSIGNABLE_TYPE, //按照类型过滤
    ASPECTJ,//按照ASPECTJ表达式过滤
    REGEX,//按照正则表达式过滤
    CUSTOM;//按照自定义的过滤规则过滤
    private FilterType() {
    }
}

4、自定义FilterType过滤规则(CUSTOM)

  • 主配置文件设置 -》FilterType.CUSTOM
@ComponentScan(value = "com.wukong",useDefaultFilters = false,
        includeFilters = {
       // @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
       // @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),
        @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})})
  • 编写自定义过滤规则 implement FilterType
public class MyTypeFilter implements TypeFilter {

    /**
     *
     * @param metadataReader  读取到的当前正在扫描类的信息
     * @param metadataReaderFactory   可以获取到其他任何类的信息的
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {

        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类的资源信息(类的路基)
        Resource resource = metadataReader.getResource();

        String className = classMetadata.getClassName();

        System.out.println("---->"+className);
        return false;
    }
}
  • 输出
---->com.wukong.bean.Person
---->com.wukong.config.MyTypeFilter
---->com.wukong.controller.BookController
---->com.wukong.dao.BookDao
---->com.wukong.service.BookService
---->com.wukong.test.IocTest
---->com.wukong.test.MyTest
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
newPerson

5、@Scope 设置组件作用域

给ioc容器添加一个组件,默认是单实例的,在单实例的情况下,ioc容器启动就会创建创建对象放到容器中。

// @Bean 默认都是单实例的

/**Scope:
 *  prototype 多实例:ioc容器启动并不会调用方法创建对象,而是每次调用方法时创建对象
 *  singleton 单实例 (默认):ioc 容器启动就会调用方法创建对象放到ioc容器中。
 *  request
 *  session
 */
@Scope("prototype")
@Bean("penson")
public Person person(){
    System.out.println("给容器中添加person方法...");
    return new Person("张三",25,"河北省衡水市");
}

6、@Lazy Bean懒加载

什么是懒加载?

懒加载,主要是针对单实例bean:默认在容器启动的时候创建对象。

懒加载:容器启动不创建对象,第一次使用(Bean)的时候创建对象,然后再初始化。

7、@Conditional 按条件注册Bean

  • @Conditional(condition[]) :按照一定的条件进行判断,满足条件给容器中注册bean。
**
 * @Conditional(condition[]:按照一定的条件进行判断,满足条件给容器中注册bean'
 * 判断条件:
 *  1、如果系统是Windows系统,给容器中注册 bill
 *  2、如果系统是Linux系统,给容器中注册linus
 */

@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person01(){
    return  new Person("Bill Gates",63,"美国加州");
}


@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02(){
    return  new Person("linus",49,"美国加州");
}
  • WindowsCondition(LinuxCondition同理)
//判断是否windows 系统
public class WindowsCondition implements Condition {

    /**
     *
     * @param conditionContext  判断能使用的上下文环境
     * @param annotatedTypeMetadata 注释信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //TODO 是否linux
        //1、能获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //2、获取类加载器
        ClassLoader classLoader = conditionContext.getClassLoader();
        //3、获取运行时的环境信息
        Environment environment = conditionContext.getEnvironment();
        //4、获取到bean定义的注册类
        BeanDefinitionRegistry registry = conditionContext.getRegistry();

        String property = environment.getProperty("os.name");

  
        if (property.contains("Windows")){
            return true;
        }


        return false;
    }
}
  • 测试
@Test
public void test03(){
    AnnotationConfigApplicationContext applicationContext =
            new AnnotationConfigApplicationContext(MainConfig2.class);

    //获取运行环境
    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    //获取操作系统的名字 Windows 10
    String property = environment.getProperty("os.name");

    System.out.println("操作系统是:"+property);

    String[] names = applicationContext.getBeanDefinitionNames();

    for (String name:names) {
        System.out.println(name);
    }

    Map<String, Person> beans = applicationContext.getBeansOfType(Person.class);
    System.out.println(beans);

}

8、@Import 给容器中快速导入一个组件

给容器中注册组件的几种方式:

  • 包扫描 + 组件标注注解(@Controller 、@Service、@Repository、@Component)
  • @Bean 【导入的第三方包里面的组件】
  • @Import 【快速给容器中导入组件】:id默认是全类名 com.wukong.bean.Color
@Configuration
@Import({Color.class,Number.class})
public class MainConfig2 {
    ...
}


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    Class<?>[] value();
}

为了方便测试,抽取一下公共方法

//抽取公共方法
private void printBeans(AnnotationConfigApplicationContext applicationContext){
    String[] names = applicationContext.getBeanDefinitionNames();
    for (String name:names) {
        System.out.println(name);
    }
}

9、@Import 使用ImportSelector

ImprotSelector :返回需要导入的组件全类名的数组。

@param annotationMetadata: 当前标注Import注解类的所有注解信息

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
}
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {

    /**
     *
     * @param annotationMetadata  当前标注Import注解类的所有注解信息
     * @return  返回值就是要导入组件中的全类名
     */
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {

        return new String[]{"com.wukong.bean.Blue","com.wukong.bean.Yellow"};
    }
}

10、@Import 使用 ImportBeanDefinitionRegistrar

public interface ImportBeanDefinitionRegistrar {
    void registerBeanDefinitions(AnnotationMetadata var1, BeanDefinitionRegistry var2);
}
  • 创建 ImportBeanRegistrar类 implements ImportBeanDefinitionRegistrar
public class MyImportBeanRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     *
     * @param annotationMetadata   当前类的注解信息
     * @param registry beanDefinition 注册类
     *   把所需要的容器添加到bean 调用 beanDefinitionRegistry.registerBeanDefinition 自定义注册
     *
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
        boolean red = registry.containsBeanDefinition("com.wukong.bean.Red");
        boolean blue = registry.containsBeanDefinition("com.wukong.bean.Blue");

        //指定bean
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainRow.class);
        if (red && blue){
            registry.registerBeanDefinition("rainRow",rootBeanDefinition);
        }

    }
}
  • 将创建的 ImportBeanRegistrar类 添加到 Import 中
@Configuration
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanRegistrar.class})
  • 测试

11、使用Spring提供的FactoryBean 注册组件

  • 创建一个spring定义的工厂bean
public class ColorFactoryBean implements FactoryBean<Color> {

    /**
     *
     * @return 返回一个Color对象,会添加到容器中
     * @throws Exception
     */
    @Override
    public Color getObject() throws Exception {
        System.out.println("ColorFactoryBean.getObject执行....");
        return new Color();
    }

    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    /**
     *
     * @return  ture:单实例 在容器中只保存一份
     *          false :多实例,每次获取都会创建一个新的bean
     */
    @Override
    public boolean isSingleton() {
        return false;
    }
}
  • 注册到容器
@Bean
public ColorFactoryBean colorFactoryBean(){
    return new ColorFactoryBean();
}
  • 测试

1、在singleton(单实例)情况下,创建两个colorFactoryBean对象,都只是容器启动的时候创建一次对象放到ioc容器中。

2、在prototype(多实例)情况下,创建两个colorFactoryBean对象,每次调用方法是创建对象。

3、Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");

默认的类型是FactoryBean.getObjectType 返回的类型,如果applicationContext.getBean("&colorFactoryBean") 在id前面加上&,则是通过id创建,创建的实例就是工厂bean的实例。

@Test
public void testImport(){
    printBeans(applicationContext);

    //工厂Bean获取的是getObject方法创建的对象
    Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
    System.out.println("colorFactoryBean的类型:"+colorFactoryBean.getClass());

}

12、@Bean指定初始化和销毁方法

**bean的生命周期:**bean创建—初始化----销毁的过程

指定 init-method=“” destroy-method=“”

  • 初始化:单实例:对象创建的时候初始化;多实例:对象调用的时候初始化
  • 销毁:单实例:容器关闭的时候进行销毁;多实例:容器不会管理bean,容器关闭,bean不进行销毁

1、创建一个对象,并创建对象构造、初始化、销毁方法、

public class Car {
    public Car() {
        System.out.println("Car Constructor");
    }

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

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

2、@Bean添加到容器 并指定initMethod、destroyMethod

@Bean(initMethod = "init",destroyMethod = "destroy")
public Car car(){
    return new Car();
}

3、测试

@Test
public void test(){
    //1、创建ioc容器
    AnnotationConfigApplicationContext applicationContext =
            new AnnotationConfigApplicationContext(MyConfigOfLifeCycle.class);
    System.out.println("容器创建完成....");

    //关闭容器
    applicationContext.close();
}

结果

Car Constructor
car.......init
容器创建完成....
car.......destroy

13、InitializingBean 和DisposableBean 接口

通过让Bean实现 InitializingBean 接口定义初始化逻辑,DisposableBean销毁逻辑

public class Cat implements InitializingBean, DisposableBean {
...
}

14、@PostConstruct @PreDestroy

JSR250:

  • @PostConstruct ,在bean创建完成并且属性赋值完成;来执行初始化方法
  • @PreDestroy,在容器bean销毁之前通知我们进行清理工作
@Component
public class Dog {

    public Dog() {
        System.out.println("dog    constructor");
    }

    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
        System.out.println("init--------->@PostConstruct");
    }

    //移除容器之前
    @PreDestroy
    public void destroy(){
        System.out.println("destroy------->@PreDestroy");
    }
}

15、BeanPostProcessor

在bean初始化前后进行一些处理工作:

  • postProcessBeforeInitialization :在初始之前工作
  • postProcessAfterInitialization:在初始化之后工作

16、BeanPostProcessor原理

遍历得到容器中所有的BeanPostProcessor;挨个执行BeforeInitialization,
一旦返回null,跳出for循环,不会执行后面的BeanPostProcessor;   

populateBean(beanName, mbd, instanceWrapper);
initializeBean
{
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}    

17、BeanPostProcessor 在spring底层的应用

Spring 底层对BeanPostProcessor 的应用:

bean 赋值,注入其他组件,@Autowired,声明周期注解功能,@Async,等等

18、@Value 赋值

 * 使用@Value赋值:
 * 1、基本数值
 * 2、可以写spring表达式 #{}
 * 3、可以写 ${} 取出配置文件中的值
@Value("张三")
private String name;    //姓名

19、@PropertySource 取出配置文件中的值

<constat:property-placeholder location="classpath:"></constat:property-placeholder>

使用@PropertySource(value = {“classpath:/person.properties”},encoding = “gbk”),来加载配置文件,保存到运行的环境遍历中。

ps:因为我的配置文件默认的是gbk编码,所以encoding 设置了 gbk ,否则出现乱码。

@Value("${person.name}")
private String name;    //姓名

20、@Autowired、@Qualifer

@Autowired:自动注入:

1、默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);

2、如果找到多个相同类型的组件,再讲属性的名称作为组件的id去容器中查找

3、@Qualifer 指定需要装配的组件id,而不是去默认的属性名

4、自动装配一定要讲属性赋值好,否则会报错

5、使用@Autowired(required = false) 可以调成非必须自动装配

6、@primary:让spring进行自动装配的时候,默认使用首选的bean

21、@Resource(JSR250) 和 @Inject

@Resource: 默认是按照组件名称进行装配的。

@Inject:需要导入javax.inject的包,和Autowired的功能一样

22、方法、构造器位置的自动装配

@Autowired :

  • 构造器位置上:如果组件只有一个有参构造器。这个有参构造器的@Autowired可以省略,参数位置的组件还是可以从容器中获取。
  • 方法:@Bean + 方法参数,方法从容器中获取,默认不写@Autowired
  • 属性

23、Autowired Spring底层

自定义组件想要使用Spring底层的一些组件(ApplicationContext,BeanFactory…)只需要实现…Aware,在创建对象的时候,会调用接口规定的方法,注入相关组件。

把Spring底层一些组件注入到自定义的Bean中。

24、@Prefile环境搭建

Profile:Spirng 为我们提供的可以根据当前环境,动态激活或者切换一系列组件的功能。

  • 给容器中添加开发环境、测试环境、生产环境数据源
@Configuration
@PropertySource("classpath:/jdbc.properties")
public class MainConfigOfProfile implements EmbeddedValueResolverAware {

    @Value("${jdbc_user}")
    private String user;

    StringValueResolver resolver;

    String driverClass;

    /**
     * 测试数据源
     * @return
     * @throws PropertyVetoException
     */
    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${jdbc_password}") String password) throws PropertyVetoException {

        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc://localhost:3306/ssm_crud");
        dataSource.setDriverClass(driverClass);

        return dataSource;
    }

    /**
     * 生产环境的数据源
     * @return
     * @throws PropertyVetoException
     */
    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${jdbc_password}") String password) throws PropertyVetoException {

        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc://localhost:3306/ssm");
        dataSource.setDriverClass(driverClass);

        return dataSource;
    }

    /**
     * 开发环境的数据源
     * @return
     * @throws PropertyVetoException
     */
    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${jdbc_password}") String password) throws PropertyVetoException {

        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl("jdbc://localhost:3306/ssm-02");
        dataSource.setDriverClass(driverClass);

        return dataSource;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.resolver = resolver;
        driverClass = resolver.resolveStringValue("${jdbc_driverClass}");
    }
}

25、@Profile 根据环境注册Bean

@Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件组件。

@Profile 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能生效

加了环境标识的bean,只有环境被激活的时候,才能被注册到容器中。默认是default环境。

切换数据源的方式:

1、使用命令行参数,在虚拟机参数位置加上:-Dspring.profile.active = 【环境标识】

2、代码方式

@Test
public void test02(){
    //1、创建一个applicationContext
    AnnotationConfigApplicationContext applicationContext =
            new AnnotationConfigApplicationContext();
    //2、设置需要激活的环境
    applicationContext.getEnvironment().setActiveProfiles("dev");
    //3、注册主配置类
    applicationContext.register(MainConfigOfProfile.class);
    //4、启动刷新容器
    applicationContext.refresh();

    String[] names = applicationContext.getBeanNamesForType(DataSource.class);

    for (String name:names) {
        System.out.println(name);
    }
}

26、IOC 完结撒花

27、AOP -功能测试

AOP:

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

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

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.13</version>
</dependency>

2、创建一个业务逻辑类

在业务逻辑运行的时候将日志进行打印,方法运行之前,运行之后,异常

//业务逻辑类
public class MathCalculator {

    public int div(int i,int j){
        return i/j;
    }
}

3、定义一个日志切面类

感知到MathCalculator.div运行到哪一步了

通知方法:

  • 前置通知(@Before)
  • 后置通知(@After)
  • 返回通知(@AfterReturning)
  • 异常通知(@AfterThrowing)
  • 环绕通知(@Around)
public class LogAspect {

    public void logStart(){
        System.out.println("除法运行...参数列表是:{}");
    }

    public void logEnd(){
        System.out.println("除法结束...");
    }

    public void logReturn(){
        System.out.println("除法正常返回...运行结果:{}");
    }

    public void logException(){
        System.out.println("除法异常....异常信息:{}");
    }
}

4、给切面了的目标方法标注何时何地运行(通知注解)

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

/**
 * 业务逻辑类
 * @return
 */
@Bean
public MathCalculator mathCalculator(){
    return new MathCalculator();
}

/**
 * 切面类
 * @return
 */
@Bean
public LogAspect logAspect(){
    return new LogAspect();
}

6、告诉spring哪个是切面类,哪个是业务逻辑类(@Aspect)

7、【重点】给配置文件加@EnableAspectJAutoProxy

开启基于注解的AOP模式,在Spring中会有很多的@EnableXXX

小结(springAOP注解实现三个步骤):

  • 将业务逻辑组件和切面类都加入到容器中,告诉Spring哪个是切面类(@Aspect)
  • 在切面类上的每一个通知方法上标注注解,告诉Spring何时何地执行切入点
  • 开启基于注解的AOP 模式@EnableAspectJAutoProxy

28、【AOP原理】 @EnableAspectJAutoProxy

  • @EnableAspectJAutoProxy
    • @Import(AspectJAutoProxyRegistrar.class):给容器中导入了AspectJAutoProxyRegistrar
      • 利用AspectJAutoProxyRegistrar自定义给容器注册bean-
      • 给容器注册了一个AnnotationAwareAspectJAutoProxyCreator
  • AnnotationAwareAspectJAutoProxyCreator:

在这里插入图片描述

AbstractAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

SmartInstantiationAwareBeanPostProcessor:后置处理器,在bean初始化之前要做的工

BeanFactoryAware:自动装配 beanFactory

29、【AOP原理】AbstractAutoProxyCreator

AbstractAutoProxyCreator .setBeanFactory()

AbstractAutoProxyCreator 有后置处理器的逻辑

在这里插入图片描述

AbstractAdvisorAutoProxyCreator.setBeanFactory()====》initBeanFactory()

AbstractAdvisorAutoProxyCreator.

AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()

30、【AOP原理】AnnotationAwareAspectJAutoProxyCreator 创建和注册流程

流程:

1、创建Ioc容器

2、注册配置类,调用refresh,刷新容器

register(annotatedClasses);
refresh();

3、registerBeanPostProcessors(beanFactory);注册bean的后置处理器,来方便拦截bean的创建。

  1. 先获取ioc容器中已经定义了的需要创建对象的所有BeanPostProcessor

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hX6E7qaJ-1651372383858)(image-20220428161642277.png)]

  1. 也给容器中加了其他的 PostProcessors
  2. 有限注册实现了 PriorityOrdered 接口的 BeanPostProcessor
  3. 再给容器中注册实现了 Ordered 接口的 BeanPostProcessor
  4. 注册没实现优先级接口的 BeanPostProcessor
  5. 注册 BeanPostProcessor 实际上就是创建 BeanPostProcessor对象保存到容器中
    1. 创建 org.springframework.aop.config.internalAutoProxyCreator 的 BeanPostProcessor
      1. 创建Bean 的实例
      2. populateBean 给bean的属性赋值
      3. initializeBean 初始化Bean
        1. invokeAwareMethods():想当与Aware接口的方法回调
        2. applyBeanPostProcessorsBeforeInitialization()应用后置处理器的 ProcessorsBeforeInitialization
        3. invokeInitMethods ():执行初始化方法
        4. applyBeanPostProcessorsAfterInitialization():执行后置处理器的PostProcessorsAfterInitialization
      4. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功
  6. 把BeanPostProcessor.addBeanPostProcessor(PostProcessor)

31、【AOP原理】AnnotationAwareAspectJAutoProxyCreator 的执行时机

AbstractAutoProxyCreator ======》InstantiationAwareBeanPostProcessor

接上文:

4、finishBeanFactoryInitialization(beanFactory); 完成BeanFactoryInitialization初始化工作,创建剩下的bean单实例

  1. 遍历容器中的所有Bean,依次创建对象getBean(beanName);

getBean >doGetBean>getSingleton

  1. 创建bean

    1. 先从缓存中获取当前bean,如果能获取到,说明当前bean是之前被创建过的,直接使用,否则在创建。

    2. createBean 创建bean

      BeanPostProcessor是在Bean对象创建完成初始化前后调用】

      InstantiationAwareBeanPostProcessor 是在Bean对象创建之前先尝试调用Bean后置处理器】

      1. resolveBeforeInstantiation(beanName, mbdToUse); 希望后置处理器在此能创建,返回一个代理对象;如果能返回代理对象就返回。

        • 后置处理器先尝试返回对象

        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

        拿到后置处理器,如果是 InstantiationAwareBeanPostProcessor 就执行后置处理器的 postProcessBeforeInstantiation()方法

        if (bean != null) {
           bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
        
      2. 如果不能 doCreateBean(beanName, mbdToUse, args) 真正创建一个bean

32、【AOP原理】 创建AOP代理

AnnotationAwareAspectJAutoProxyCreatorInstantiationAwareBeanPostProcessor 】的作用:

1、在每一个Bean创建之前,调用 postProcessBeforeInstantiation

关心业务逻辑bean 和日志切面bean的创建

  1. 判断当前bean 是否在 advisedBeans 中,保存了所有需要增强的bean
  2. 判断当前bean 是否是基础类型的 Advice 、Pointcut、Advisor、AopInfrastructureBean 或者是否是切面(@Aspect)
  3. 是否需要跳过 shouldSkip()
    1. 获取候选的增强器(切面里的通知方法) List candidateAdvisors = findCandidateAdvisors();
    2. 每一个封装的通知方法都增强器:InstantiationAwareBeanPostProcessor
    3. 判断每一个增强器是否是 AspectJPointcutAdvisor
    4. 永远返回 false

2、创建对象 ==》调用 postProcessAfterInitialization

1. return wrapIfNecessary(bean, beanName, cacheKey); //包装如果需要的情况下
    	1. 获取当前bean的所有增强方法,
    	2. 找到能在当前bean使用的增强器(找哪些通知方法是需要切入Bean方法的)
    	3. 给增强器排序
2. 保存当前bean 在adviseBeans中
3. 如果当前bean需要增强,创建bean都代理对象
    	1. 获取所有增强器(通知方法)
    	2. 保存ProxyFactory
    	3. 创建代理对象

33、【AOP原理】获取拦截器链 MethodInterceptor

1、目标方法执行:

容器中保存了组件的代理对象(cglib增强后的对象),这里面保存了详细信息,比如增强器、目标对象等。

	1. CglibAopPorxy.intercept();拦截目标执行方法
	1. 根据ProxyFactory对象获取拦截器链

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

  1. 如果没有拦截器链,直接执行目标方法
    • List interceptorList 创建List对象保存拦截器
    • 遍历所有的增强器,将其转为 interceptor registry.getInterceptors(advisor);
    • 将增强器转为 List interceptors ,如果是MethodInterceptor则:interceptors.add((MethodInterceptor) advice); 如果不是,AdvisorAdapter转为 interceptors,返回MethodInterceptor 数组。
    • 拦截器链就是每一个通知方法又被包装为方法拦截器,又称为 MethodInterceptor机制
  2. 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入一个CglibMethodInvocation对象,调用他的 proceed()方法。

34、链式调用通知方法

5个拦截器

在这里插入图片描述

new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

执行:CglibMethodInvocation.proceed();

利用:currentInterceptorIndex 来记录当前拦截器索引

拦截器链的触发过程

1)、如果没有拦截器执行目标方法,或者拦截器的索引数 -1 是 -1(执行到最后一个拦截器)

2)、链式获取没一个拦截器,拦截器执行invoke方法,拦截器等待下一个拦截器执行完成返回以后在执行。

35、【AOP原理】总结

  • @EnableAspectJAutoProxy 开启AOP功能
  • @EnableAspectJAutoProxy会给容器中导入一个 AspectJAutoProxyRegistrar
  • AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器
  • 容器创建流程:
    • registerBeanPostProcessors(beanFactory);注册bean的后置处理器,来方便拦截bean的创建。
    • finishBeanFactoryInitialization()初始化剩下的单实例bean
      • 创建业务逻辑组件和切面组件
      • AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
      • 当组件创建完成之后,判断组件是否需要增强
        • 是:切面的通知方法,包装成(Advisor);给业务逻辑创建一个代理对象(cglib)
  • 执行目标方法:
    • 代理对象执行目标方法
    • CglibAopPorxy.intercept();拦截目标执行方法
      • 得到目标方法的增强器,包装成拦截器
      • 利用拦截器的链式机制,依次进入每一个拦截器进行执行;
      • 效果:
        • 前置通知 – 目标方法 – 后置通知 --{正常执行:返回通知;异常:异常通知}

36、37、声明式事务

声明式事务:

环境:

  1. 导入相关依赖(数据源、数据库、spring-jdbc)
  2. 配置数据源、JdbcTemplate 操作数据库 JdbcTemplate :spring提供的简化数据库操作的数据
  3. 给方法上标志 @Transactional 标志当前方法是一个事务方法
  4. @EnableTransactionManagement 开启基于注解的事务管理功能
  5. 配置事务管理器,来管理事务 PlatformTransactionManager

38、【原理】事务声明

1、@EnableTransactionManagement ===》@Import({TransactionManagementConfigurationSelector.class}) 给容器中导入两个组件;

AutoProxyRegistrarProxyTransactionManagementConfiguration

2、AutoProxyRegistrar:给容器中注册了一个,ImportBeanDefinitionRegistrar利用后置处理器机制,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链执行调用。

3、ProxyTransactionManagementConfiguration

​ 1)、给容器中注册事务增强器,事务增强器要用事务注解的属性,来解析事务。AnnotationTransactionAttributeSource

​ 2)、拦截器 transactionInterceptor 保存了事务的属性信息,保存了事务管理器

他是一个 MethodInterceptor 在目标方法执行的时候,执行拦截器链,

事务拦截器:

1、先获取事务相关的属性

2、 在获取PlatfromTransactionManager

3、执行目标方法,如果异常,获取到事务管理器,利用事务管理器回滚;如果正常利用事务管理器提交事务。

39、【扩展原理】BeanFactoryPostProcessor

扩展原理

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

**BeanFactoryPostProcessor:**beanFactory的后置处理器,在BeanFactory标志初始化后调用,所有的bean已经保存加载到 BeanFactory 里了,但是bean还没有被加载。

  1. ioc 创建对象
  2. invokeBeanFactoryPostProcessors(beanFactory),执行BeanFactoryPostProcessor:
    1. 直接在BeanFactory 找到所有类型是 BeanFactoryPostProcessor: 的组件
    2. 在初始化创建其他组件前面执行

40、【扩展原理】BeanDefinitionRegistryPostProcessor

postProcessBeanDefinitionRegistry();

在所有bean定义信息,将要被加载,bean实例还没哟被创建的时候;在 BeanFactoryPostProcessor之前执行

BeanFactory 就是按照 BeanDefinitionRegistryPostProcessor 里面保存的信息创建每一个bean实例的。

原理:

  1. ioc创建对象
  2. refresh()==》invokeBeanFactoryPostProcessors(beanFactory);
  3. 从容器中获取到所有的 BeanDefinitionRegistryPostProcessor组件
    1. 先触发 postProcessBeanDefinitionRegistry()方法
    2. 再来触发postProcessBeanFactory() 方法

41、【扩展原理】ApplicationListener

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

@FunctionalInterface
public interface  <E extends ApplicationEvent> extends EventListener {}

步骤:

1、写一个监听器来监听某个事件,(ApplicationEven及其子类)

2、把监听器加入到容器;

3、只要容器中有相关事件的发布,我们就能监听到这个事件

ContextRefreshedEvent :容器刷新完成(所有bean都会完成创建)会发布这个事件

ContextClosedEvent:关闭容器会发布这个事件

4、发布一事件:

//发布一个事件
applicationContext.publishEvent(new ApplicationEvent( new String("我发布一个事件")) {
});

42、ApplicationListener 原理

ContextRefreshedEvent

  1. 容器创建对象:refresh()
  2. finishRefresh( ); 容器刷新完成
  3. publishEvent(new ContextRefreshedEvent(this));
  4. 事件的发布流程:
    1. 获取到事件的多播器(派发器):getApplicationEventMulticaster()
    2. multicastEvent 派发事件
    3. 获取到所有的 ApplicationListener :ApplicationListener<?> listener :
      1. 如果有 Executor 可以进行异步派发
      2. 否则执行 listener invokeListener(listener, event); 拿到listener 回调onApplicationEvent()

Test$1[source=我发布一个事件]

ContextClosedEvent

【事件多播器(派发器)】

1)、容器创建对象:refresh()

2)、initApplicationEventMulticaster;初始化

1. 先去容器找有没有 id = applicationEventMulticaster 组件
2. 如果没有  new SimpleApplicationEventMulticaster()并且加入到容器中	

【容器中有那些监听器】

1. 容器创建对象:refresh();
1. registerListeners() 从容器中拿到所有的监听器,把他们注册到 ApplicationEventMulticaster

43、【扩展原理】@EventListener

原理是使用 EventListenerMethodProcessor 来解析 @EventListener

SmartInitializingSingleton 原理:

1)、ioc容器创建对象并刷新 refresh()

2)、finishBeanFactoryInitialization();初始化剩下的单实例bean

  • 先创建所有的单实例bean getbean();
  • 获取所有创建好的单实例bean ,判断是否为SmartInitializingSingleton
  • 如果是就调用 afterSingletonsInstantiated()

44、【spring容器创建】

Spring容器的创建 refresh()

  • prepareRefresh(); 刷新前的预处理

    • initPropertySources(); 初始化一些属性设置;子类自定义属性个性化的属性设置方法
    • getEnvironment().validateRequiredProperties(); 属性校验,检验属性的合法
    • this.earlyApplicationEvents = new LinkedHashSet<>(); 保存容器中一些事件
  • obtainFreshBeanFactory(); 获取bean工厂

  • refreshBeanFactory(); 创建bean工厂

  • getBeanFactory 获取bean工厂;返回GenericApplicationContext创建的bean工厂

  • 将创建的beanFactory 返回

  • prepareBeanFactory(beanFactory); BeanFactory 的预准备工作,对beanFactory 做一些设置

    • 设置BeanFactory 的类加载器、支持表达式解析器
    • 添加了部分 BeanPostProcessor【addBeanPostProcessor】
    • 设置忽略的自动装配的接口 EnvironmentAware 等
    • 注册可以解析的自动装配,可以在任何组件中自动注入 【BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext】
    • beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    • 添加编译时的AspectJ;
  • postProcessBeanFactory() 准备工作完成后的后置处理工作

  • invokeBeanFactoryPostProcessors(beanFactory); 执行BeanFactoryPostProcessors

    • BeanFactoryPostProcessors:作用 BeanFactory 的后置处理器,在bean标准化之后执行的
    • 执行BeanFactoryPostProcessors
      • 获取所有的 BeanDefinitionRegistryPostProcessor
      • 看优先级排序 PriorityOrdered 优先级接口的BeanDefinitionRegistryPostProcessor
      • 在执行实现了 Ordered 顺序接口的
      • 最后执行没有实现任何优先级或者是顺序接口的 BeanDefinitionRegistryPostProcessor
  • registerBeanPostProcessors(beanFactory); 注册BeanPostProcessors

    • 获取所有的BeanPostProcessors:

    不同接口类型的BeanPostProcessor;在bean创建前后的执行时机是不一样的

    • DestructionAwareBeanPostProcessor (org.springframework.beans.factory.config)
      SmartInstantiationAwareBeanPostProcessor
      InstantiationAwareBeanPostProcessor (org.springframework.beans.factory.config)

      MergedBeanDefinitionPostProcessor

    • 获取所有的BeanPostProcessor;后置处理器都默认可以通过 PriorityOrdered、Ordered接口来指定优先级

    • 先注册 PriorityOrdered 优先级的 BeanPostProcessor

    • 在注册 Ordered接口的

    • 最后注册没有实现任何优先级接口的。

    • 注册MergedBeanDefinitionPostProcessor

    • 注册一个ApplicationListener

  • ​ initMessageSource(); 初始好MessageSource 组件,做国际化功能,消息绑定,消息解析。

    • 获取 BeanFactory
    • 看容器中是否有 id 为 messageSource的组件
      • 如果有 赋值为messageSource属性
      • 如果没有就创建一个 DelegatingMessageSource
    • 把创建好的messageSource 注册在容器中,以后获取国际化配置文件值的时候,可以自动注入。
  • initApplicationEventMulticaster();初始化事件派发器

    • 获取BeanFactory
    • 从BeanFactory获取 applicationEventMulticaster
    • 若没有配置就创建一个SimpleApplicationEventMulticaster
    • 将创建的applicationEventMulticaster 注入到容器中 以后其他组件也可以自动注入。
  • onRefresh(); 留给子容器的(子类)

    • 可以重写 onRefresh()方法
  • registerListeners(); 给容器中将所有项目里面的 ApplicationListener

    • 从容器中拿到所有的 applicationListener 组件 getApplicationListeners
    • 将没有getApplicationListeners添加到 事件派发器中 getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    • 派发之前步骤产生的事件;
  • **finishBeanFactoryInitialization(beanFactory);**初始化所有剩下的单实例bean

    • preInstantiateSingletons() 初始化剩下的单实例bean
      • 获取中的所有bean,依次进行初始化和创建对象
    • 获取bean的定义信息 RootBeanDefinition
    • ​ 判断 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit())
      • 判断是否是 实现Factorybean 接口的bean
      • 不是工厂bean,利用getBean创建对象 ==》doGetBean
        • 先获取缓存中保存的单实例bean。如果能获取到,说明这个bean是被创建的
        • 缓存中拿不到,就创建一个bean
        • 标记当前bean已经被创建了
        • 获取bean的定义信息
        • 获取当前bean依赖的其他bean,如果有按照 getBean的方式把bean创建出来
  • finishRefresh();完成BeanFactory的初始化创建工作,IOC容器就创建完成

  • 总结:

    1. Spring容器在启动的时候,先会保存所有的bean定义的信息

      1. xml注册bean
      2. 注解注册bean:@Service 、@Component、@Bean 等等
    2. Spring容器会在合适的时机创建这些Bean

      1. 用到这些bean的时候,利用getBean方法创建bean;创建好保存在容器中
      2. 统一创建所有bean的时候
    3. 后置处理器:每一个bean创建完成之后,都会使用各种后置处理器,进行处理来增强bean的功能。

      AutowiredAnnotationBeanPostProcessor:处理自动注入

    4. 事件驱动模型

      ApplicationListener :事件监听

      ApplicationEventMulticaster:事件派发

tMulticaster

  • 若没有配置就创建一个SimpleApplicationEventMulticaster

  • 将创建的applicationEventMulticaster 注入到容器中 以后其他组件也可以自动注入。

  • onRefresh(); 留给子容器的(子类)

    • 可以重写 onRefresh()方法
  • registerListeners(); 给容器中将所有项目里面的 ApplicationListener

    • 从容器中拿到所有的 applicationListener 组件 getApplicationListeners
    • 将没有getApplicationListeners添加到 事件派发器中 getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    • 派发之前步骤产生的事件;
  • **finishBeanFactoryInitialization(beanFactory);**初始化所有剩下的单实例bean

    • preInstantiateSingletons() 初始化剩下的单实例bean
      • 获取中的所有bean,依次进行初始化和创建对象
    • 获取bean的定义信息 RootBeanDefinition
    • ​ 判断 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit())
      • 判断是否是 实现Factorybean 接口的bean
      • 不是工厂bean,利用getBean创建对象 ==》doGetBean
        • 先获取缓存中保存的单实例bean。如果能获取到,说明这个bean是被创建的
        • 缓存中拿不到,就创建一个bean
        • 标记当前bean已经被创建了
        • 获取bean的定义信息
        • 获取当前bean依赖的其他bean,如果有按照 getBean的方式把bean创建出来
  • finishRefresh();完成BeanFactory的初始化创建工作,IOC容器就创建完成

  • 总结:

    1. Spring容器在启动的时候,先会保存所有的bean定义的信息

      1. xml注册bean
      2. 注解注册bean:@Service 、@Component、@Bean 等等
    2. Spring容器会在合适的时机创建这些Bean

      1. 用到这些bean的时候,利用getBean方法创建bean;创建好保存在容器中
      2. 统一创建所有bean的时候
    3. 后置处理器:每一个bean创建完成之后,都会使用各种后置处理器,进行处理来增强bean的功能。

      AutowiredAnnotationBeanPostProcessor:处理自动注入

    4. 事件驱动模型

      ApplicationListener :事件监听

      ApplicationEventMulticaster:事件派发

举报

相关推荐

Spring 注解开发

Spring注解开发

spring注解开发

spring注解开发(7)

14.0、Spring注解开发

Spring纯注解开发

注解开发Spring AOP

Spring 注解开发详解

0 条评论