SpringAOP和IOC

本文深入讲解Spring框架的核心概念,包括IOC容器的管理机制、组件添加与注入的方式、配置类的使用,以及AOP原理和应用。

SpringAOP和IOC

容器

IOC

@Configuration

定义person类

public class Person {
    private String name;
    private Integer age;

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.tl.bean.Person">
        <property name="age" value="18"></property>
        <property name="name" value="zhangsan"></property>
    </bean>
</beans>

测试


public class MainTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext= new ClassPathXmlApplicationContext("beans.xml");
        Person person = (Person)applicationContext.getBean("person");
        System.out.println(person);
    }
}

使用javaconfig配置文件


//配置类==配置文件
@Configuration //告诉Spring这是一个配置文件
public class MainConfig {

    //给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
    @Bean
    public Person person(){
        return new Person("lisi",20);
    }
}

测试


public class MainTest {
    public static void main(String[] args) {
//        ApplicationContext applicationContext= new ClassPathXmlApplicationContext("beans.xml");
//        Person person = (Person)applicationContext.getBean("person");
//        System.out.println(person);
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);
    }
    //获得bean中方法的名字
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
        for (String s : beanNamesForType) {
            System.out.println(s);
        }
}

@ComponentScan
<!--    包扫描 只要标注了@Controller @Service @Repository @Component等注解就会自动扫描包-->
    <context:component-scan base-package="com.tl.bean"></context:component-scan>
    <bean id="person" class="com.tl.bean.Person">
        <property name="age" value="18"></property>
        <property name="name" value="zhangsan"></property>
    </bean>

等价于


//配置类==配置文件
@Configuration //告诉Spring这是一个配置文件
@ComponentScan(value = "com.tl")
public class MainConfig {

    //给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
    @Bean("person")
    public Person person01(){
        return new Person("lisi",20);
    }
}
public class IOCTest {
    @Test
    public void test01(){
        //IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String s : beanDefinitionNames) {
            System.out.println(s);
        }
    }

}

输出

mainConfig
bookController
bookDao
bookService
person

指定排除规则

@ComponentScan(value = "com.tl",excludeFilters = {
        @ComponentScan.Filter(type= FilterType.ANNOTATION,classes = {Controller.class, Service.class})
}) //value指定要扫描的包
@ComponentScan(value = "com.tl",excludeFilters = {
        @ComponentScan.Filter(type= FilterType.ANNOTATION,classes = {Service.class})
},includeFilters = {
  @ComponentScan.Filter(type=FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false) //value指定要扫描的包,默认开启全部扫描
//FilterType.ANNOTATION 按照注解
//ANNOTATION, 按照注解
//        ASSIGNABLE_TYPE, 按照给定的类型 BookService
//        ASPECTJ, 使用ASPECTJ表达式
//        REGEX, 使用正则指定
//        CUSTOM; 使用自定义规则

自定义过滤规则


public class MyTypeFilter implements TypeFilter {
    @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;
    }
}

@Scope
@ComponentScan(value = "com.tl",excludeFilters = {
        @ComponentScan.Filter(type= FilterType.ANNOTATION,classes = {Service.class})
},includeFilters = {
//  @ComponentScan.Filter(type=FilterType.ANNOTATION,classes = {Controller.class}),
        @ComponentScan.Filter(type=FilterType.CUSTOM,classes = {MyTypeFilter.class})
},useDefaultFilters = false) //value指定要扫描的包,默认开启全部扫描
//配置类==配置文件
@Configuration //告诉Spring这是一个配置文件
public class MainConfig2 {

    //给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
    @Bean("person")
    @Scope
    public Person person01(){
        return new Person("wangwu",25);
    }
}
@Test
public void test02(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    for (String s : beanDefinitionNames) {
        System.out.println(s);
    }
    Object bean = applicationContext.getBean("person");
    Object bean2 = applicationContext.getBean("person");
    //默认是单实例的
    System.out.println(bean == bean2);

}
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";

多实例:IOC容器启动不会去调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象

单实例:ioc容器启动会调用方法创建对象放在ioc容器中,以后每次获取就是直接从容器中拿

request:同一次请求创建一个实例

session:同一个session创建一个实例

@Scope调整作用域

懒加载

容器启动不创建对象,在第一次使用bean的时候 创建对象,并初始化

//给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
@Bean("person")
@Scope
@Lazy
public Person person01(){
    System.out.println("给容器中添加person");
    return new Person("wangwu",25);
}

先创建ioc容器,只有在使用加载person类时才会加载

@Conditional

按照一定的条件进行判断,满足条件给容器注册bean

/**
 * 如果系统是windows,给容器中注册darlene
 * 如果是linux系统,给容器中注册dar
 * @return
 */
@Bean("darlene")
@Conditional({WindowsCondition.class})
public Person person02(){
    return new Person("darlene",22);
}

@Bean("dar")
@Conditional({LinuxCondition.class})
public Person person03(){
    return new Person("dar",33);
}
//判断是否是Linux系统
public class LinuxCondition implements Condition {
    /**
     * ConditionContext:判断条件能使用的上下文环境
     * AnnotatedTypeMetadata:注释信息
     * @param conditionContext
     * @param annotatedTypeMetadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //是否是linux系统
        //1.获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory listableBeanFactory = conditionContext.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = conditionContext.getClassLoader();
        //获取环境 包括环境变量和虚拟机变量
        Environment environment = conditionContext.getEnvironment();
        //获取到bean定义的注册类
        BeanDefinitionRegistry definitionRegistry = conditionContext.getRegistry();
        String property = environment.getProperty("os.name");
        if(property.contains("linux")){
            return true;
        }
        return false;
    }
}

测试

@Test
public void test03(){
    String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);

    //获取环境变量的值 Windows 10
    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    String r = environment.getProperty("os.name");
    System.out.println(r);


    for (String s : beanNamesForType) {
        System.out.println(s);
    }
    Map<String, Person> persons = applicationContext.getBeansOfType(Person.class);
    System.out.println(persons);
}

更改虚拟机设置,变为linux系统

-Dos.name=linux

@Conditional如果配置在类上,只有满足当前条件,这个类中配置的所有bean注册才能生效,类中组件统一设置

给容器中注册组件:

  1. 包扫描+组件标注注解(@Controller/@Service/@Respository/@Component),自己写的类

  2. @Bean【导入的第三方包里面的注解】

  3. @Import 【快速给容器中导入一个组件】

    1. @Import(要导入容器中的组件),容器中就会自动注册这个组件,id默认是全类名
    //配置类==配置文件
    @Configuration //告诉Spring这是一个配置文件
    @Import(Color.class)
    public class MainConfig2 {
    
    @Test
    public void testImport(){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
    
    1. ImportSelector:返回要导入的组件的全类名数组

      //自定义逻辑返回需要导入的组件
      public class MyImportSelector implements ImportSelector {
          //返回值就是要导入到容器中的组件全类名
          //AnnotationMetadata:当前标注@Import注解的类的所有注释信息
          @Override
          public String[] selectImports(AnnotationMetadata annotationMetadata) {
      //        annotationMetadata
              //方法不要返回null值
              return new String[]{"com.tl.bean.Blue","com.tl.bean.Yellow"};
          }
      }
      
      @Test
      public void testImport(){
          String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
          for (String beanDefinitionName : beanDefinitionNames) {
              System.out.println(beanDefinitionName);
          }
      }
      
    2. ImportBeanDefinitionRegistrar

      public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
          /**
           * AnnotationMetadata importingClassMetadata: 当前类的注解信息
           * BeanDefinitionRegistry registry: BeanDefinition注册类,把所有需要添加到容器中的bean,调用BeanDefinitionRegistry.registerBeanDefinition手动注册进来
           * BeanNameGenerator importBeanNameGenerator:
           * @param importingClassMetadata
           * @param registry
           * @param importBeanNameGenerator
           */
          @Override
          public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
              boolean blue = registry.containsBeanDefinition("com.tl.bean.Blue");
              boolean yellow = registry.containsBeanDefinition("com.tl.bean.Yellow");
              if(yellow && blue){
                  //指定bean定义信息,bean的类型,bean。。。
                  RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
                  //注册bean,指定bean名
                  registry.registerBeanDefinition("rainBow", beanDefinition);
              }
      
          }
      }
      
  4. 使用Spring提供的FactoryBean工厂Bean

    public class ColorFactoryBean implements FactoryBean<Color> {
        //返回一个color对象,这个对象会添加在容器中
        @Override
        public Color getObject() throws Exception {
            System.out.println("ColorFactoryBean...getObject");
            return new Color();
        }
    
        @Override
        public Class<?> getObjectType() {
            return Color.class;
        }
    
        //是否是单例
        //true 这个bean是单实例,在容器中会保存一分
        //false 多实例,每次获取都会创建一个新的bean
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
    
    @Test
    public void testImport(){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
        //bean的类型 bean的类型:class com.tl.bean.Color
        System.out.println("bean的类型:"+colorFactoryBean.getClass());
    }
    

    注册工厂,实际上获取到的是color对象

    1. 默认获取到的是工厂bean调用getObject创建的对象
    2. 要获取工厂Bean本身,我们需要给id前面加一个&
Bean生命周期
@Component
public class Cat implements InitializingBean, DisposableBean {
    public Cat() {
        System.out.println("cat constructor");
    }

    //销毁方法
    @Override
    public void destroy() throws Exception {
        System.out.println("cat destory");
    }

    //初始化方法,在配置文件加载之后
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat afterPropertiesSet");
    }
}
/**
 * bean的生命周期,
 * bean->创建 ---初始化---销毁
 * 容器管理bean的生命周期
 * 自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
 *构造(对象创建)
 *  单实例:在容器启动的时候创建对象
 *  多实例:在每次获取的时候创建对象
 *初始化:对象创建完成,并赋值好,调用初始化方法
 * 销毁:
 *  单实例,容器关闭的时候
 *  多实例,容器不会管理这个bean,容器不会调用销毁方法
 *
 *  遍历得到容器中所有的BeanPostProcessor,挨个执行beforeInitialization
 *  一旦返回null,就跳出循环,不会执行后面的BeanPostProcessor,postProcessors
 *  BeanPostProcessor原理
 *  populateBean(beanName,mbd,instanceWrapper)给bean进行属性赋值
 *  initializeBean{
 *      applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)
 *      invokeInitMethods(beanName,wrappedBean,mbd);执行自定义初始化
 *      applyBeanPostProcessorAfterInitalization(wrappedBean,beanName)
 *  }
 *1.指定初始化和销毁方法
 *  通过@Bean指定init-method destory-method
 *2.通过让bean实现InitializingBean(定义初始化逻辑)
 *  DisposableBean销毁逻辑
 *3.可以使用JSR250
 *  @PostConstruct,在bean创建完成并且属性赋值完成,未执行初始化方法
 *  @PreDestory,在容器销毁bean之前通知我们进行清理工作
 *4.BeanPostProcessor bean的后置处理器
 *  在bean初始化前后进行一些处理工作
 *  postProcessBeforeInitialization:在初始化之前进行工作
 *  postProcessAfterInitialization:在初始化之后进行工作
 *
 *  Spring底层对BeanPostProcessor的使用
 *          bean赋值,注入其他组件 @Autowired 生命周期注解功能
 */
@ComponentScan("com.tl.bean")
public class MainConfigOfLifeCircle {
    @Bean(initMethod = "init",destroyMethod = "destory")
//    @Scope("prototype") //多实例时不会再次创建
    public Car car(){
        return new Car();
    }
}

@Component
public class Dog implements ApplicationContextAware {
    public Dog() {
        System.out.println("dog constructor...");
    }
    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
        System.out.println("Dog...@PostConstruct");
    }
    //容器移除对象之前
    @PreDestroy
    public void destory(){
        System.out.println("Dog...@PreDestroy");
    }
    ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

public class IOCTest_LifeCycle {
    @Test
    public void test01(){
        //1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCircle.class);
        printBeans(applicationContext);
        System.out.println("容器创建完成....");
        //关闭容器
        applicationContext.close();
    }
    private void printBeans(AnnotationConfigApplicationContext applicationContext){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }
}
//postProcessBeforeInitialization...mainConfigOfLifeCircle=>com.tl.config.MainConfigOfLifeCircle@35fc6dc4
//        postProcessAfterInitialization...mainConfigOfLifeCircle=>com.tl.config.MainConfigOfLifeCircle@35fc6dc4
//        cat constructor
//        postProcessBeforeInitialization...cat=>com.tl.bean.Cat@731f8236
//        cat afterPropertiesSet
//        postProcessAfterInitialization...cat=>com.tl.bean.Cat@731f8236
//        dog constructor...
//        postProcessBeforeInitialization...dog=>com.tl.bean.Dog@4f9a3314
//        Dog...@PostConstruct
//postProcessAfterInitialization...dog=>com.tl.bean.Dog@4f9a3314
//        car constructor
//        postProcessBeforeInitialization...car=>com.tl.bean.Car@2b4a2ec7
//        car ---init---
//        postProcessAfterInitialization...car=>com.tl.bean.Car@2b4a2ec7
//        org.springframework.context.annotation.internalConfigurationAnnotationProcessor
//        org.springframework.context.annotation.internalAutowiredAnnotationProcessor
//        org.springframework.context.annotation.internalCommonAnnotationProcessor
//        org.springframework.context.event.internalEventListenerProcessor
//        org.springframework.context.event.internalEventListenerFactory
//        mainConfigOfLifeCircle
//        cat
//        dog
//        myBeanPostProcessor
//        car
//        容器创建完成....
//        car----- destory-----
//        Dog...@PreDestroy
//cat destory

源码

populateBean:给bean进行属性赋值

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
    } else {
        if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
            Iterator var4 = this.getBeanPostProcessors().iterator();

            while(var4.hasNext()) {
                BeanPostProcessor bp = (BeanPostProcessor)var4.next();
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        return;
                    }
                }
            }
        }

        PropertyValues pvs = mbd.hasPropertyValues() ? mbd.getPropertyValues() : null;
        int resolvedAutowireMode = mbd.getResolvedAutowireMode();
        if (resolvedAutowireMode == 1 || resolvedAutowireMode == 2) {
            MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
            if (resolvedAutowireMode == 1) {
                this.autowireByName(beanName, mbd, bw, newPvs);
            }

            if (resolvedAutowireMode == 2) {
                this.autowireByType(beanName, mbd, bw, newPvs);
            }

            pvs = newPvs;
        }

        boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = mbd.getDependencyCheck() != 0;
        PropertyDescriptor[] filteredPds = null;
        if (hasInstAwareBpps) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }

            Iterator var9 = this.getBeanPostProcessors().iterator();

            while(var9.hasNext()) {
                BeanPostProcessor bp = (BeanPostProcessor)var9.next();
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
                    PropertyValues pvsToUse = ibp.postProcessProperties((PropertyValues)pvs, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                        if (filteredPds == null) {
                            filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                        }

                        pvsToUse = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvsToUse == null) {
                            return;
                        }
                    }

                    pvs = pvsToUse;
                }
            }
        }

        if (needsDepCheck) {
            if (filteredPds == null) {
                filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }

            this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);
        }

        if (pvs != null) {
            this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
        }

    }
}

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

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            //遍历得到容器中所有的BeanPostProcessor,挨个执行BeforeInitialization,一旦返回null,跳出for循环,不会执行后面的BeanPostProcessor,PostProcessorsBeforeInitialization
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
            this.invokeInitMethods(beanName, wrappedBean, mbd); //执行自定义初始化
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }

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

        return wrappedBean;
    }

属性赋值

编写配置文件

@Configuration
public class MainConfigOfPropertyValues {

    @Bean
    public Person person(){
        return new Person();
    }
}

Person类

public class Person {
    /**
     * 使用@Value赋值
     * 1.基本数值
     * 2.可以写SpEL,#{}
     * 3.可以写${},取出配置文件中的值(在运行环境变量里面的值)
     */
    @Value("张三")
    private String name;
    @Value("#{20-2}")
    private Integer age;

编写测试类

public class IOCTest_PropertyValue {
    //1.创建IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
    @Test
    public void test01(){
        printBeans(applicationContext);
        System.out.println("容器创建完成....");
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);
        //关闭容器
        applicationContext.close();
    }
    private void printBeans(AnnotationConfigApplicationContext applicationContext){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }
}
配置文件
person.name=zhangsan
@PropertySource(value = "classpath:/person.properties")
@Configuration
public class MainConfigOfPropertyValues {

    @Bean
    public Person person(){
        return new Person();
    }
}
@Value("${person.name}")
private String nickName;

public String getNickName() {
    return nickName;
}

public void setNickName(String nickName) {
    this.nickName = nickName;
}

测试

public class IOCTest_PropertyValue {
    //1.创建IOC容器
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
    @Test
    public void test01(){
        printBeans(applicationContext);
        System.out.println("容器创建完成....");
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);

        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        String property = environment.getProperty("person.name");
        System.out.println(property);
        //关闭容器
        applicationContext.close();
    }
    private void printBeans(AnnotationConfigApplicationContext applicationContext){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }
}
自动装配

自动装配:Spring利用依赖注入DI,完成堆IOC容器中哥哥组件的依赖关系映射

  1. @Autowired自动注入
    1. 默认优先按照类型取容器中找对应的组件

    2. 如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找 applicationContext.getBean(BookDao.class);

    3. @Qualifier("")明确指定要装配的组件的id 而不是使用属性名

    4. 自动装配默认一定要将属性赋值好,没有就会报错,可以使用@Autowired(required=false)

    5. @Primary 让Spring进行自动装配的使用,默认使用首选的bean

@Service
public class BookService {
    @Autowired
    private BookDao bookDao;
}
@ComponentScan({"com.tl.service","com.tl.dao","com.tl.controller"})
@Configuration
public class MainConfigOfAutowired {

}

测试

public class IOCTest_Autowired {
    @Test
    public void test01(){
        //1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
        BookService bookService = applicationContext.getBean(BookService.class);
        System.out.println(bookService);
        //容器中的bookDao 默认优先按照类型取容器中找对应的组件
        BookDao bean = applicationContext.getBean(BookDao.class);
        System.out.println(bean);
        //关闭容器
        applicationContext.close();
    }
    private void printBeans(AnnotationConfigApplicationContext applicationContext){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }
}
//    BookService{bookDao=com.tl.dao.BookDao@36c88a32}
//com.tl.dao.BookDao@36c88a32
  1. Spring支持使用@Resource(JSR250)和@Inject(JSR330)[java规范的注解],可以脱离Spring框架使用,@Autowired依赖Spring框架

    @Resource:

    ​ 可以和@Autowired一样实现自动装配功能,默认时按照组件名称进行自动装配,没有能支持@Primary功能,没有支持@Autowired(required=false)

    @Inject:需要导入javax.inject包,和@Autowired的功能一样,没有required=false的功能

    //    @Autowired
    //    @Resource
        @Inject
        private BookDao bookDao;
        public void print(){
            System.out.println(bookDao);
        }
    

AutowiredAnnotationBeanPostProcessor支持解析Autowired注解

  1. @Autowired:构造器,参数,方法,属性。都是从容器中获取参数组件的值

    1. 标注在方法位置 @Bean+方法参数,参数从容器中获取,默认不屑Autowired,都能自动装配
    @Component
    public class Car {
        public Car() {
            System.out.println("car constructor");
        }
        public void init(){
            System.out.println("car ---init---");
        }
        public void destory(){
            System.out.println("car----- destory-----");
        }
    }
    
    @Component
    public class Boss {
    
        @Autowired
        private Car car;
    
        public Car getCar() {
            return car;
        }
    
        @Autowired //标注在方法上,Spring容器创建当前对象,就会调用该方法,完成赋值
        //方法使用的参数,自定义类型的值从ioc容器中获取
        public void setCar(Car car) {
            this.car = car;
        }
    
        @Override
        public String toString() {
            return "Boss{" +
                    "car=" + car +
                    '}';
        }
    
    }
    
    public class IOCTest_Autowired {
        @Test
        public void test01(){
            //1.创建IOC容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
            BookService bookService = applicationContext.getBean(BookService.class);
            System.out.println(bookService);
            //容器中的bookDao
    //        BookDao bean = applicationContext.getBean(BookDao.class);
    //        System.out.println(bean);
            Boss bean = applicationContext.getBean(Boss.class);
            System.out.println(bean);
            Car car = applicationContext.getBean(Car.class);
            System.out.println(car);
            //关闭容器
            applicationContext.close();
        }
        private void printBeans(AnnotationConfigApplicationContext applicationContext){
            String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
            for (String name : beanDefinitionNames) {
                System.out.println(name);
            }
        }
    }
    //postProcessBeforeInitialization...mainConfigOfAutowired=>com.tl.config.MainConfigOfAutowired$$EnhancerBySpringCGLIB$$e58fbceb@5dd6264
    //        postProcessAfterInitialization...mainConfigOfAutowired=>com.tl.config.MainConfigOfAutowired$$EnhancerBySpringCGLIB$$e58fbceb@5dd6264
    //        postProcessBeforeInitialization...bookDao=>com.tl.dao.BookDao@60d8c9b7
    //        postProcessAfterInitialization...bookDao=>com.tl.dao.BookDao@60d8c9b7
    //        postProcessBeforeInitialization...bookService=>BookService{bookDao=com.tl.dao.BookDao@60d8c9b7}
    //        postProcessAfterInitialization...bookService=>BookService{bookDao=com.tl.dao.BookDao@60d8c9b7}
    //        postProcessBeforeInitialization...bookController=>com.tl.controller.BookController@65466a6a
    //        postProcessAfterInitialization...bookController=>com.tl.controller.BookController@65466a6a
    //        car constructor
    //        postProcessBeforeInitialization...car=>com.tl.bean.Car@418e7838
    //        postProcessAfterInitialization...car=>com.tl.bean.Car@418e7838
    //        postProcessBeforeInitialization...boss=>Boss{car=com.tl.bean.Car@418e7838}
    //        postProcessAfterInitialization...boss=>Boss{car=com.tl.bean.Car@418e7838}
    //        cat constructor
    //        postProcessBeforeInitialization...cat=>com.tl.bean.Cat@470f1802
    //        cat afterPropertiesSet
    //        postProcessAfterInitialization...cat=>com.tl.bean.Cat@470f1802
    //        dog constructor...
    //        postProcessBeforeInitialization...dog=>com.tl.bean.Dog@72a7c7e0
    //        Dog...@PostConstruct
    //postProcessAfterInitialization...dog=>com.tl.bean.Dog@72a7c7e0
    //        BookService{bookDao=com.tl.dao.BookDao@60d8c9b7}
    //        Boss{car=com.tl.bean.Car@418e7838}
    //        com.tl.bean.Car@418e7838
    //        Dog...@PreDestroy
    //cat destory
    
    1. 标注在构造器上,如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取

      //默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
      @Component
      public class Boss {
      
      //    @Autowired
          private Car car;
      
          //构造器用的组件,都是从容器中获取
          @Autowired
          public Boss(Car car) {
              this.car = car;
              System.out.println("boss constructor");
          }
      
          public Car getCar() {
              return car;
          }
      
         // @Autowired //标注在方法上,Spring容器创建当前对象,就会调用该方法,完成赋值
          //方法使用的参数,自定义类型的值从ioc容器中获取
          public void setCar(Car car) {
              this.car = car;
          }
      
          @Override
          public String toString() {
              return "Boss{" +
                      "car=" + car +
                      '}';
          }
      
      }
      
      1. 放在参数位置

        //不用component加载
        public class Color {
            private Car car;
        
            public Car getCar() {
                return car;
            }
        
            public void setCar(Car car) {
                this.car = car;
            }
        
            @Override
            public String toString() {
                return "Color{" +
                        "car=" + car +
                        '}';
            }
        }
        
        @ComponentScan({"com.tl.service","com.tl.dao","com.tl.controller","com.tl.bean"})
        @Configuration
        public class MainConfigOfAutowired {
            /**
             * @bean标注的方法在创建对象的时候,方法参数的值从容器中获取
             * @param car
             * @return
             */
            @Bean
            public Color color(Car car){
                Color color = new Color();
                color.setCar(car);
                return color;
            }
        
        }
        
        public class IOCTest_Autowired {
            @Test
            public void test01(){
                //1.创建IOC容器
                AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
                BookService bookService = applicationContext.getBean(BookService.class);
                System.out.println(bookService);
                //容器中的bookDao
        //        BookDao bean = applicationContext.getBean(BookDao.class);
        //        System.out.println(bean);
                Boss bean = applicationContext.getBean(Boss.class);
                System.out.println(bean);
                Car car = applicationContext.getBean(Car.class);
                System.out.println(car);
        
                Color color  = applicationContext.getBean(Color.class);
                System.out.println(color);
                //关闭容器
                applicationContext.close();
            }
            private void printBeans(AnnotationConfigApplicationContext applicationContext){
                String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
                for (String name : beanDefinitionNames) {
                    System.out.println(name);
                }
            }
        }
        //postProcessBeforeInitialization...mainConfigOfAutowired=>com.tl.config.MainConfigOfAutowired$$EnhancerBySpringCGLIB$$53d5c7df@1534f01b
        //        postProcessAfterInitialization...mainConfigOfAutowired=>com.tl.config.MainConfigOfAutowired$$EnhancerBySpringCGLIB$$53d5c7df@1534f01b
        //        postProcessBeforeInitialization...bookDao=>com.tl.dao.BookDao@69b2283a
        //        postProcessAfterInitialization...bookDao=>com.tl.dao.BookDao@69b2283a
        //        postProcessBeforeInitialization...bookService=>BookService{bookDao=com.tl.dao.BookDao@69b2283a}
        //        postProcessAfterInitialization...bookService=>BookService{bookDao=com.tl.dao.BookDao@69b2283a}
        //        postProcessBeforeInitialization...bookController=>com.tl.controller.BookController@49b0b76
        //        postProcessAfterInitialization...bookController=>com.tl.controller.BookController@49b0b76
        //        car constructor
        //        postProcessBeforeInitialization...car=>com.tl.bean.Car@1622f1b
        //        postProcessAfterInitialization...car=>com.tl.bean.Car@1622f1b
        //        boss constructor
        //        postProcessBeforeInitialization...boss=>Boss{car=com.tl.bean.Car@1622f1b}
        //        postProcessAfterInitialization...boss=>Boss{car=com.tl.bean.Car@1622f1b}
        //        cat constructor
        //        postProcessBeforeInitialization...cat=>com.tl.bean.Cat@5bd03f44
        //        cat afterPropertiesSet
        //        postProcessAfterInitialization...cat=>com.tl.bean.Cat@5bd03f44
        //        dog constructor...
        //        postProcessBeforeInitialization...dog=>com.tl.bean.Dog@e056f20
        //Dog...@PostConstruct
        //postProcessAfterInitialization...dog=>com.tl.bean.Dog@e056f20
        //postProcessBeforeInitialization...color=>Color{car=com.tl.bean.Car@1622f1b}
        //        postProcessAfterInitialization...color=>Color{car=com.tl.bean.Car@1622f1b}
        //        BookService{bookDao=com.tl.dao.BookDao@69b2283a}
        //        Boss{car=com.tl.bean.Car@1622f1b}
        //        com.tl.bean.Car@1622f1b
        //        Color{car=com.tl.bean.Car@1622f1b}
        //        Dog...@PreDestroy
        //cat destory
        
      2. 自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx),自定义组件实现xxAware,在创建对象的时候,会调用接口规定的方法注入相关组件,Aware

        把Spring容器底层的一些组件注入到自定义的bean中

        @Component
        public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
            private ApplicationContext applicationContext;
            @Override
            public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
                System.out.println("传入的ioc:"+applicationContext);
                this.applicationContext = applicationContext;
            }
        
            @Override
            public void setBeanName(String s) {
                System.out.println("当前bean的名字:"+s);
            }
        
            @Override
            public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
                stringValueResolver.resolveStringValue("你好${os.name} 我是#{20*18}");
                System.out.println("解析的字符串:"+stringValueResolver);
            }
        }
        //postProcessBeforeInitialization...mainConfigOfAutowired=>com.tl.config.MainConfigOfAutowired$$EnhancerBySpringCGLIB$$2cd670b0@79b06cab
        //        postProcessAfterInitialization...mainConfigOfAutowired=>com.tl.config.MainConfigOfAutowired$$EnhancerBySpringCGLIB$$2cd670b0@79b06cab
        //        postProcessBeforeInitialization...bookDao=>com.tl.dao.BookDao@2473d930
        //        postProcessAfterInitialization...bookDao=>com.tl.dao.BookDao@2473d930
        //        postProcessBeforeInitialization...bookService=>BookService{bookDao=com.tl.dao.BookDao@2473d930}
        //        postProcessAfterInitialization...bookService=>BookService{bookDao=com.tl.dao.BookDao@2473d930}
        //        postProcessBeforeInitialization...bookController=>com.tl.controller.BookController@3ba9ad43
        //        postProcessAfterInitialization...bookController=>com.tl.controller.BookController@3ba9ad43
        //        car constructor
        //        postProcessBeforeInitialization...car=>com.tl.bean.Car@29626d54
        //        postProcessAfterInitialization...car=>com.tl.bean.Car@29626d54
        //        boss constructor
        //        postProcessBeforeInitialization...boss=>Boss{car=com.tl.bean.Car@29626d54}
        //        postProcessAfterInitialization...boss=>Boss{car=com.tl.bean.Car@29626d54}
        //        cat constructor
        //        postProcessBeforeInitialization...cat=>com.tl.bean.Cat@4b0b0854
        //        cat afterPropertiesSet
        //        postProcessAfterInitialization...cat=>com.tl.bean.Cat@4b0b0854
        //        dog constructor...
        //        postProcessBeforeInitialization...dog=>com.tl.bean.Dog@67a20f67
        //        Dog...@PostConstruct
        //postProcessAfterInitialization...dog=>com.tl.bean.Dog@67a20f67
        //        当前bean的名字:red
        //        解析的字符串:org.springframework.beans.factory.config.EmbeddedValueResolver@459e9125
        //        传入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@6842775d, started on Thu Sep 23 11:32:45 CST 2021
        //        postProcessBeforeInitialization...red=>com.tl.bean.Red@7cc0cdad
        //        postProcessAfterInitialization...red=>com.tl.bean.Red@7cc0cdad
        //        postProcessBeforeInitialization...color=>Color{car=com.tl.bean.Car@29626d54}
        //        postProcessAfterInitialization...color=>Color{car=com.tl.bean.Car@29626d54}
        //        BookService{bookDao=com.tl.dao.BookDao@2473d930}
        //        Boss{car=com.tl.bean.Car@29626d54}
        //        com.tl.bean.Car@29626d54
        //        Color{car=com.tl.bean.Car@29626d54}
        //        Dog...@PreDestroy
        //cat destory
        

        xxxAware,功能:使用xxxProcessor,ApplicationContextAware ==>ApplicationContextAwareProcessor

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qggyghH5-1632410932981)(Spring源码学习.assets/image-20210923113643335.png)]

        public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
            Object result = existingBean;
        
            Object current;
            for(Iterator var4 = this.getBeanPostProcessors().iterator(); var4.hasNext(); result = current) {
                BeanPostProcessor processor = (BeanPostProcessor)var4.next();
                current = processor.postProcessBeforeInitialization(result, beanName);
                if (current == null) {
                    return result;
                }
            }
        
            return result;
        }
        
        this.invokeInitMethods(beanName, wrappedBean, mbd);
        
profile

Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能

开发环境,测试环境,生产环境

@Profile

  1. 创建一个applicationContext

  2. 设置需要激活的环境

  3. 注册主配置类

  4. 启动刷新容器

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

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

  7. 没有标注环境标识的bean在任何环境下都是加载的

总结
AnnotationConfigApplicationContext
组件添加
  1. ComponentScan
  2. Bean
  3. Configuration
  4. Component
  5. Service
  6. Controller
  7. Repository
  8. Conditional 按照条件给容器中注册bean
  9. Primary
  10. Lazy
  11. Scope
  12. Import 给容器中导入需要的bean
  13. ImportSelector
  14. 工厂模式
组件赋值
  1. @Value
  2. @Autowired
    1. @Qualifier
    2. @Resource(JSR250)
    3. @Inject(JSR330 需要导入javax.inject)
  3. @PropertySource
  4. @PropertySources
  5. @Profile
    1. Environment
    2. -Dspring.profiles.active=test
组件注入
  1. 方法参数
  2. 构造器注入
  3. ApplicationContextAware->ApplicationContextAwareProcessor
  4. xxxAware

AOP

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

  1. 导入aop模块 Spring AOP(spring-aspects)

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

  3. 定义一个日志切面类(LogAspects),切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行。通知方法:前置通知(@Before logStart,在目标方法div运行之前进行通知),后置通知(@After在目标方法运行结束之后进行通知),返回通知(@AfterReturning在目标方法正常返回之后运行),异常通知(@AfterThrowing在目标方法运行出现异常执行),环绕通知(@Around动态代理,手动推进目标方法运行joinPoint.proceed())

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

    public class LogAspects {
        //抽取公告的切入点表达式
        //1.本类引用
        //2.其它的切面引用
        @Pointcut("execution(public int com.tl.aop.MathCalculator.*(..))")
        public void pointCut(){
    
        }
    
        //Before在目标方法之前切入,切入点表达式(指定在哪个方法切入)
        @Before("pointCut()")
        public void logStart(){
            System.out.println("除法运行。。。参数列表是{}");
        }
    
        //无论方法是正常结束还是异常结束
        @After("pointCut()")
        public void logEnd(){
            System.out.println("除法结束。");
        }
        @AfterReturning("pointCut()")
        public void logReturn(){
            System.out.println("除法正常返回。。。运行结果是,{}");
        }
        @AfterThrowing("pointCut()")
        public void logException(){
            System.out.println("除法异常。。异常信息,{}");
        }
    }
    
  5. 将切面类和业务逻辑类(目标方法所在类都加入到容器中)

  6. 必须告诉Spring哪个类是切面类(给切面类上添加注解@Aspect)

  7. 给配置类中加@EnableAspectJAutoProxy,开启基于注解的aop模式

    @EnableAspectJAutoProxy
    @Configuration
    public class MainConfigOfAop {
        //将业务逻辑类加入到容器中
        @Bean
        public MathCalculator calculator(){
            return new MathCalculator();
        }
        //窃密那类加入到容器中
        @Bean
        public LogAspects logAspects(){
            return new LogAspects();
        }
    }
    

    测试

    public class IOCTest_AOP {
        @Test
        public void test01(){
            //1.创建IOC容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
            MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
            mathCalculator.div(1,1);
            //关闭容器
            applicationContext.close();
        }
        private void printBeans(AnnotationConfigApplicationContext applicationContext){
            String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
            for (String name : beanDefinitionNames) {
                System.out.println(name);
            }
        }
    }
    //除法运行。。。参数列表是{}
    //        MathCalculator...div
    //        除法正常返回。。。运行结果是,{}
    //        除法结束。
    

//告诉Spring当前类是一个切面类
@Aspect
public class LogAspects {
    //抽取公告的切入点表达式
    //1.本类引用
    //2.其它的切面引用
    @Pointcut("execution(public int com.tl.aop.MathCalculator.*(..))")
    public void pointCut(){

    }

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

    //无论方法是正常结束还是异常结束
    @After("pointCut()")
    public void logEnd(JoinPoint joinPoint){
        System.out.println(joinPoint.getSignature().getName()+"结束。");
    }
    @AfterReturning(value="pointCut()",returning = "result")
    public void logReturn(JoinPoint joinPoint,Object result){
        System.out.println(joinPoint.getSignature().getName()+"正常返回。。。运行结果是,{"+result+"}");
    }
    @AfterThrowing(value="pointCut()",throwing = "exception")
    public void logException(JoinPoint joinPoint,Exception exception){
        System.out.println(joinPoint.getSignature().getName()+"异常。。异常信息,{"+exception+"}");
    }
}

三步
  1. 将业务逻辑组件和切面类都加入到容器中,告诉Spring哪个是切面类@Aspect
  2. 在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
  3. 开启基于注解的aop模式@EnableAspectJAutoProxy
AOP原理

看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么

  1. @EnableAspectJAutoProxy

    1. @Import({AspectJAutoProxyRegistrar.class}) 给容器中导入AspectJAutoProxyRegistrar
    2. 利用AspectJAutoProxyRegistrar自定义给容器中注册bean AspectJAutoProxyRegistrar=org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
    3. 给容器中注册一个AnnotationAwareAspectJAutoProxyCreator
  2. AnnotationAwareAspectJAutoProxyCreator

    —>AnnotationAwareAspectAutoProxyCreator

    ---->AbstractAdvisorAutoProxyCreator

    —>AbstractAutoProxyCreator

    ---->extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

    关注后置处理器BeanPostProcessor,,在bean初始化完成前后做的事情,自动装配BeanFactory

AbstractAutoProxyCreator.setBeanFactory

AbstractAutoProxyCreator有后置处理器的逻辑postProcessBeforeInstantiation

AbstractAdvisorAutoProxyCreator.setBeanFactory->setBeanFactory()

AnnotationAwareAspectAutoProxyCreator.initBeanFactory

  1. 传入配置类,创建IOC容器

  2. 注册配置类,调用refresh()刷新容器

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        this();
        this.register(componentClasses);
        this.refresh();
    }
    
  3. registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建

    1. 先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
    2. 给容器中加别的BeanPostProcessor
    3. 优先注册实现类PriorityOrdered接口的BeanPostProcessor
    4. 在容器中注册实现类Ordered接口的BeanPostProcessor
    5. 注册没实现优先级接口的BeanPostProcessor
    6. 注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中,创建internalAutoProxyCreator的BeanPostProcessor[AnnotationAwareAspectJAutoProxyCreator]
      1. 创建Bean的实例
      2. populateBean,给bean的各种属性赋值
      3. initializeBean:初始化bean
        1. invokeAwareMethods()处理Aware接口的方法回调
        2. applyBeanPostProcessorsBeforeInitialization()应用后置处理器的postProcessBeforeInitialization()
        3. invokeInitMethods()执行自定义的初始化方法
      4. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功==>aspectJAdvisorBuilder
    7. 把BeanPostProcessor注册到BeanFactory中,beanFactory.addBeanPostProcessor(postProcessor)

以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程

AnnotationAwareAspectJAutoProxyCreator =》InstantializationAwareBeanPostProcessor

  1. finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作,创建剩下的单实例bean

    1. 遍历获取容器中所有bean,一次创建对象getBean(beanName) getBean->doGetBean()->getSingleton()->

    2. 创建bean

      1. 先从缓存中获取当前bean,如果获取到,说明bean是之前被创建过的,直接使用,否则再创建。只要创建好bean都会被缓存起来

      2. createBean();创建Bean AnnotationAwareAspectJAutoProxyCreator 会在任何bean创建之前先尝试返回bean的实例

        ​ BeanPostProcessor实在Bean对象创建完成初始化前后调用的

        InstantiationAwareBeanPostProcessor是在创建Bean是之前先尝试用后置处理器返回

        1. resolvBeforeInstantiation(),解析BeforeInstantialization,希望后置处理器在此能返回一个代理对象,如果不能就继续

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

            bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            //拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor就执行postProcessBeforeInstantiation
            if (bean != null) {
                bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
            
        2. doCreateBean(beanName,mbdToUse,args) 真正的去创建一个bean实例

我觉得我属实是有点不自量力了

AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】的作用

  1. 每一个bean创建之前,调用postProcessBeforeInstantiation() 关心MathCalculator和LogAspect的创建

    1. 判断当前bean是否在advisedBeans中(保存了所有需要增强bean)
    2. 判断当前bean是否是基础类型 Advice Pointcut Advisor AopInfrastructureBean 或者是否是切面
    3. 是否需要跳过
      1. 获取候选的增强器(切面里面的增强器) 每一个封装的通知方法的增强器是InstantiationModelAwarePointcutAdvisor 判断每一个增强器是否是AspectJPointcutAdvisor类型的,返回true
      2. 永远返回false
  2. 创建对象 postProcessAfterInitialization,如果需要的时候进行包装

    1. 获取当前bean的所有增强器(通知方法)
      1. 找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
      2. 获取到能在bean中使用的增强
      3. 给增强器排序
    2. 保存当前bean在advisedBeans中
    3. 如果当前bean需要增强,创建当前bean的代理对象
      1. 获取所有增强器(通知方法)
      2. 保存到proxyFactory
      3. 创建代理对象 JDKDynamicAopProxy(jdk动态代理) ObjenesisCglibAopProxy(config) cglib动态代理(cglib的动态代理)
      4. 给容器中返回当前组件使用cglib增强了的代理对象
      5. 以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程
  3. 目标方法执行:容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象)

    1. cglibAopProxy的intercept();拦截目标方法的执行

    2. 根据proxyFactory对象获取将要执行的目标方法将要执行的拦截器链

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

      1. List interceptorList保存所有拦截器 5 一个默认的ExposeInvocationInterceptor和四个增强器

        AdvisedSupport.MethodCacheKey cacheKey = new AdvisedSupport.MethodCacheKey(method);
        List<Object> cached = (List)this.methodCache.get(cacheKey);
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        
        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
        
      2. 遍历所有的增强器,将其转为Interceptor,registry.getInterceptors(advisor)

      3. 将增强器转为List,如果是MethodInterceptor,直接加入到集合中,如果不是

    3. 如果没有拦截器链,直接执行目标方法

    4. 如果有拦截器链,把需要执行的目标对象和目标方法,拦截器链等信息传入创建一个CglibMethodInvocation对象并调用Object retval = mi.proceed()

      @Nullable
      public Object proceed() throws Throwable {
          if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
              return this.invokeJoinpoint();
          } else {
              Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
              if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                  InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                  Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
                  return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
              } else {
                  return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
              }
          }
      
      @Nullable
      public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
          Object oldProxy = null;
          boolean setProxyContext = false;
          Object target = null;
          TargetSource targetSource = this.advised.getTargetSource();
      
          Object var16;
          try {
              if (this.advised.exposeProxy) {
                  oldProxy = AopContext.setCurrentProxy(proxy);
                  setProxyContext = true;
              }
      
              target = targetSource.getTarget();
              Class<?> targetClass = target != null ? target.getClass() : null;
              List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
              Object retVal;
              if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                  Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                  retVal = methodProxy.invoke(target, argsToUse);
              } else {
                  retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
              }
      
              retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
              var16 = retVal;
          } finally {
              if (target != null && !targetSource.isStatic()) {
                  targetSource.releaseTarget(target);
              }
      
              if (setProxyContext) {
                  AopContext.setCurrentProxy(oldProxy);
              }
      
          }
      
          return var16;
      }
      
    5. 拦截器链的触发过程

      1. 如果没有拦截器执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(执行到了最后一个拦截器)执行目标方法

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pgi3QCHI-1632410932983)(Spring源码学习.assets/image-20210923225557835.png)]

      2. 链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行,拦截器链的机制保证通知方法与目标方法的执行顺序

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

原本在程序中手动创建对象的控制权,交给Spring框架来管理,IOC容器是Spring实现IOC的载体,IOC容器实际上就是个Map,Map中存放的时各种对象

对象之间的相互依赖关系交给IOC容器进行管理,由IOC容器完成对象的注入。可以简化应用的开发,把应用从复杂的依赖关系中解放出来。IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件或者注解,完全不用考虑对象是如何创建出来的,在Spring中使用beans.xml进行对象的配置,在后面的时候改为SpringBoot注解进行配置,只需要使用注解就可以配置,使用AnnotationConfigApplicationContext定义一个IOC容器,然后进行组件添加和组件赋值以及组件注入

组件添加
  1. ComponentScan
  2. Bean
  3. Configuration
  4. Component
  5. Service
  6. Controller
  7. Repository
  8. Conditional 按照条件给容器中注册bean
  9. Primary
  10. Lazy
  11. Scope
  12. Import 给容器中导入需要的bean
  13. ImportSelector
  14. 工厂模式
组件赋值
  1. @Value
  2. @Autowired
    1. @Qualifier
    2. @Resource(JSR250)
    3. @Inject(JSR330 需要导入javax.inject)
  3. @PropertySource
  4. @PropertySources
  5. @Profile
    1. Environment
    2. -Dspring.profiles.active=test
组件注入
  1. 方法参数
  2. 构造器注入
  3. ApplicationContextAware->ApplicationContextAwareProcessor
  4. xxxAware

XML----读取----》Resource----解析----》BeanDefinition----注册—》BeanFactory

AOP

AOP能够将哪些与业务无关,却为业务模块所共同调用的逻辑或者责任(比如事务处理,日志管理,权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,有利于未来的可扩展性和可维护性

基于动态代理模式,如果要代理的对象,实现了某个接口,Spring AOP会使用JdkDynamicAopProxy,去创建代理对象,对于没有实现接口的对象,就无法使用JdkDynamicAopProxy去进行代理,使用CglibAopProxy,生成一个被代理对象的子类来作为代理

运行时增强

AspectJ主要用于编译时增强,基于字节码操作,切面太多时选择这个,速度更快

  1. @EnableAspectJAutoProxy 开启AOP功能
  2. @EnableAspectJAutoProxy 会给容器中注册一个组件AnnotationAwareAspectJAutoProxyCreator
  3. AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
  4. 容器的创建过程:
    1. registerBeanPostProcessors()注册后置处理器,创建AnnotationAwareAspectJAutoProxyCreator
    2. finishBeanFactoryInitialization()初始化剩下的单实例bean
      1. 创建业务逻辑组件和切面组件
      2. AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
      3. 组件创建完成之后,判断组件是否需要增强时:切面的通知方法,包装成增强器(Advisor),给业务逻辑组件创建一个代理对象
  5. 执行目标方法
    1. 代理对象要执行目标方法
    2. CglibAopProxy.intercept()
      1. 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
      2. 利用拦截器的链式机制,依次进入每一个拦截器进行执行
      3. 效果:
        1. 正常执行:前置通知-----目标方法----------后置通知-----返回通知
          ComponentScan
  6. Bean
  7. Configuration
  8. Component
  9. Service
  10. Controller
  11. Repository
  12. Conditional 按照条件给容器中注册bean
  13. Primary
  14. Lazy
  15. Scope
  16. Import 给容器中导入需要的bean
  17. ImportSelector
  18. 工厂模式
组件赋值
  1. @Value
  2. @Autowired
    1. @Qualifier
    2. @Resource(JSR250)
    3. @Inject(JSR330 需要导入javax.inject)
  3. @PropertySource
  4. @PropertySources
  5. @Profile
    1. Environment
    2. -Dspring.profiles.active=test
组件注入
  1. 方法参数
  2. 构造器注入
  3. ApplicationContextAware->ApplicationContextAwareProcessor
  4. xxxAware

XML----读取----》Resource----解析----》BeanDefinition----注册—》BeanFactory

AOP

AOP能够将哪些与业务无关,却为业务模块所共同调用的逻辑或者责任(比如事务处理,日志管理,权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,有利于未来的可扩展性和可维护性

基于动态代理模式,如果要代理的对象,实现了某个接口,Spring AOP会使用JdkDynamicAopProxy,去创建代理对象,对于没有实现接口的对象,就无法使用JdkDynamicAopProxy去进行代理,使用CglibAopProxy,生成一个被代理对象的子类来作为代理

运行时增强

AspectJ主要用于编译时增强,基于字节码操作,切面太多时选择这个,速度更快

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值