Home > Java > javaTutorial > Detailed analysis of the life cycle of beans created by java Spring

Detailed analysis of the life cycle of beans created by java Spring

WBOY
Release: 2022-10-06 09:00:27
forward
1324 people have browsed it

This article brings you relevant knowledge about java, which mainly introduces issues related to the life cycle of beans created by Spring. Let's take a look at it together. I hope it will be helpful to everyone.

Detailed analysis of the life cycle of beans created by java Spring

Recommended learning: "java Video Tutorial"

1.Bean creation life cycle

UserService. class —> No-argument constructor (inferred constructor) —> Ordinary object —> Dependency injection (assigning values ​​to properties with @Autowired) —> Before initialization (executing with @PostConstruct method) —> Initialization (execute the afterPropertiesSet method that implements the InitializingBean interface) —> After initialization (execute AOP related Logic) —> Proxy object —> Bean

is similar to: boy —> Dependency injection —> man

##General process As follows:

    Use the constructor of the class to instantiate an object (but if there are multiple constructors in a class, Spring will choose, this is called
  • Inferred construction method)
  • After getting an object, Spring will determine whether there are attributes annotated by
  • @Autowired in the object, find these attributes and use them by Spring Perform assignment (Dependency injection)
  • After dependency injection, Spring will determine whether the object implements the
  • BeanNameAware interface, BeanClassLoaderAware interface, BeanFactoryAware interface, if implemented, means that the current object must implement setBeanName(), setBeanClassLoader(), setBeanFactory()# defined in the interface ##method, then Spring will call these methods and pass in the corresponding parameters (Aware callback)After the Aware callback, Spring will determine whether a method in the object is
  • #@PostConstruct
  • Annotated, if it exists, Spring will call this method of the current object (Before initialization)Following this, Spring will determine whether the object has been implemented
  • InitializingBean
  • Interface, if implemented, means that the current object must implement the afterPropertiesSet() method in the interface, then Spring will call afterPropertiesSet() in the current object. Method (Initialization)Finally, Spring will determine whether the current object needs to be
  • AOP
  • . If not, the Bean will be created. If AOP is required, then Dynamic proxying will be performed and a proxy object will be generated as a Bean (After initialization)
When Spring creates a Bean based on the UserService class:

If AOP is not required, then the Bean is the object obtained by the constructor method of the UserService class.
  • If AOP is required, then the Bean is the object instantiated by the UserService proxy class, not the object obtained by the UserService itself.
After the Bean object is created:

If the current Bean is
    Single Bean
  • , then the Bean object will be Store a Map. The key of the Map is beanName and the value is the Bean object. In this way, the corresponding Bean object can be obtained directly from the Map the next time you getBean. (Actually, in the Spring source code, this Map is Single Case Pool) If the current Bean is a prototype Bean, then there will be no other subsequent actions and a Map will not be stored next time. When getBean, the above creation process will be executed again to obtain a new Bean object.
Inferred constructor method:

If there is a parameterless constructor in a class, Spring will use this parameterless constructor by default. method.
  • If there is only one parameterized constructor in a class, Spring will use this parameterized constructor.
  • If there are multiple parameterized constructors in a class and no parameterless constructor, Spring will report an error.
  • If you want to specify which constructor Spring uses, you can add
  • @Autowired
  • to the constructor.
@Bean

will override @Compoment

Note:

If Spring selects A constructor with parameters is created. When Spring calls this constructor with parameters, it needs to pass in parameters. So where does this parameter come from?

Spring will find the Bean object in the Spring container based on the type and name of the input parameter (taking a singleton Bean as an example, Spring will find it from the Map in the singleton pool):

  • First search based on the input parameter type. If only one is found, use it directly as the input parameter
  • If multiple are found based on the type, then determine the only one based on the input parameter name
  • If it is not found in the end, an error will be reported and the current Bean object cannot be created.

Determine which construction method to use and determine the Bean object that enters the parameters. This process is called Inferred construction method.

2. The general process of Spring AOP

AOP is to perform dynamic proxy. In the process of creating a bean, Spring will determine the current bean being created in the last step. Does the Bean need to perform AOP? If so, it will perform dynamic proxying.

How to determine whether the current Bean object requires AOP operation:

  • First find all the aspect beans in the Spring container.
  • Traverse each aspect bean, and then traverse each method in each aspect bean to see if annotations such as @Before and @After are written.
  • If written, it will be judged whether the Pointcut corresponding to the method matches the class of the current Bean object.
  • If it matches, it means that the current Bean object needs to be processed. AOP operated.

After finding a match in the third step above, all matching methods will be cached. When executing aspect methods later, they can be quickly taken out from the cache to improve execution efficiency.

The general process of using cglib to perform AOP:

  • Generate the proxy class UserServiceProxy, and the proxy class inherits UserService
  • The proxy class overrides the methods of the parent class, such as the test() method in UserService. There will also be a target attribute in the proxy class, and the value of this attribute is the object being proxied (that is, through the UserService class Infer objects instantiated by the constructor, objects that have undergone dependency injection, initialization, etc.)
  • The logic of when the test() method in the proxy class is executed is as follows:
    • Execute aspect logic (@Before)
    • Call target.test()

When When we get the Bean object of UserService from the Spring container, we get the object generated by UserServiceProxy, which is the proxy object.

Call UserService proxy object.test() —> Execute aspect logic —> target.test(). Note that the target object is not a proxy object, but the proxied object.

UserServiceProxy(代理类) ---> 代理对象 ---> 代理对象.target = 普通对象
代理对象.test();

class UserServiceProxy extends UserService {
  
  UserService target;
  
  public void test() {
    // 执行切面逻辑 @Before --> 从匹配的切面方法的缓存中拿出来
    
    target.test(); // 调用普通对象的test方法
    
  }
  
}
Copy after login

3.Spring transaction

When we add the @Transactional annotation to a method, it means that the method will start the Spring transaction when it is called, and The Bean object corresponding to the class where this method is located will be the proxy object of the class.

Steps when the proxy object of Spring transaction executes a method:

  • Determine whether the currently executed method exists@TransactionalAnnotation
  • If it exists, use the transaction manager (TransactionMananger) to create a database connection
  • Modify the autocommit of the database connection to false
  • Execute target.test(), execute the business logic code written by the programmer, that is, execute sql
  • If no exception occurs after execution, submit, otherwise roll back

Judgment criteria for whether Spring transactions will fail: When a method annotated with @Transactional is called, it must be judged whether it is directly called by the proxy object. If so, the transaction will take effect. If not, it will Invalid.

UserServiceProxy(代理类) ---> 代理对象 ---> 代理对象.target = 普通对象
代理对象.test();

class UserServiceProxy extends UserService {
  
  UserService target;
  
  public void test() {
    // 1.先看看方法上面有没有加@Transactional
    // 2.通过事务管理器dataSource,创建一个数据库连接conn
    // 3.设置conn.autocommit = false,表示不自动提交事务
    
    target.test(); // 调用普通对象的test方法
    
    conn.commit(); // 如果方法都执行成功,那就手动提交事务
    conn.rollback(); // 如果某个方法执行失败,那就会回滚事务
    
  }
  
}
Copy after login

Detailed analysis of the life cycle of beans created by java Spring

4.Spring source code reading foreplay

BeanDefinition

BeanDefinition represents Bean definition, and there are many properties in BeanDefinition. To describe the characteristics of a Bean.

For example:

  • class, represents the Bean type
  • scope, represents the Bean Scope, singleton or prototype, etc.
  • lazyInit: Indicates whether the Bean is lazy loaded
  • initMethodName: Indicates what should be executed when the Bean is initialized Method
  • destroyMethodName: Indicates that there are many methods to be executed when the Bean is destroyed...

Declarative definition of Bean:

Beans can be defined in the following ways:

  • ##<bean/>
  • @Bean
  • @Component (@Service, @Controller)
You can also define Bean programmatically

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
context.registerBeanDefinition("user", beanDefinition);

System.out.println(context.getBean("user"));
Copy after login
You can also set a Bean through BeanDefinition Other attributes

beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载
Copy after login

Declaratively defined and programmatically defined beans will eventually be parsed by Spring into corresponding BeanDefinition objects and placed in the Spring container.

BeanDefinitionReader

Next, we will introduce several common BeanDefinition readers in Spring source code (

BeanDefinitionReader)

AnnotatedBeanDefinitionReader

You can directly convert a class into

BeanDefinition, and the annotations on the class will be parsed, for example:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);

// 将User.class解析为BeanDefinition
annotatedBeanDefinitionReader.register(User.class);

System.out.println(context.getBean("user"));
Copy after login

它能解析的注解有:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description

XmlBeanDefinitionReader

可以解析<bean/>标签

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
        int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");

        System.out.println(context.getBean("user"));
Copy after login

ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner是扫描器,它的作用和BeanDefinitionReader类似,可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在 @Component 注解,那么就会把这个类解析成为一个BeanDefinition

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.refresh();

        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
        scanner.scan("cn.xx");

        System.out.println(context.getBean("user"));
Copy after login

BeanFactory

BeanFactory表示Bean工厂,所以很明显,BeanFactory会负责创建Bean,并且提供获取Bean的API。

而ApplicationContext是BeanFactory的一种,在Spring源码中,是这么定义的:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
  MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
            ...
}
Copy after login

首先,在Java中,接口是可以多继承的,我们发现ApplicationContext继承了ListableBeanFactoryHierarchicalBeanFactory,而 ListableBeanFactory 和HierarchicalBeanFactory 都继承至 BeanFactory,所以我们可以认为 ApplicationContext 继承了BeanFactory,相当于苹果继承水果,宝马继承汽车一样,ApplicationContext 也是 BeanFactory 的一种,拥有 BeanFactory 支持的所有功能,不过 ApplicationContext 比 BeanFactory 更加强大,ApplicationContext 还继承了其他接口,也就表示 ApplicationContext 还拥有其他功能,比如MessageSource 表示国际化,ApplicationEventPublisher 表示事件发布,EnvironmentCapable 表示获取环境变量等等,关于 ApplicationContext 后面再详细讨论。

在Spring的源码中,当我们new一个ApplicationContext时,其底层会new一个BeanFactory,当使用ApplicationContext的某些方法时,比如getBean(),底层调用的就是BeanFactory的getBean()方法。

在Spring源码中,BeanFactory接口存在一个非常重要的实现类是:DefaultListableBeanFactory,也是非常核心的。

所以,我们可以直接使用DefaultListableBeanFactory,而不需要使用 ApplicationContext 的某个实现类,比如:

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(User.class);
        beanFactory.registerBeanDefinition("user", beanDefinition);
        System.out.println(beanFactory.getBean("user"));
Copy after login

DefaultListableBeanFactory是非常强大的,支持很多功能,可以通过查看DefaultListableBeanFactory 的类继承结构图:

Detailed analysis of the life cycle of beans created by java Spring

  • AliasRegistry:Supports alias function, one name can correspond to multiple aliases
  • BeanDefinitionRegistry:Can register, save, remove, and obtain a certain
  • BeanDefinitionBeanFactory: Bean factory, you can get a Bean object based on the name, type, or alias of a bean
  • SingletonBeanRegistry: Yes Directly register and obtain a singletonBean
  • SimpleAliasRegistry:It is a class that implements the functions defined in the AliasRegistry interface and supports the alias function
  • ListableBeanFactory: On the basis of BeanFactory, other functions are added. You can obtain the beanNames of all BeanDefinitions. You can obtain the corresponding beanNames according to a certain type. You can obtain the {type: corresponding Bean} mapping relationship
  • HierarchicalBeanFactory:Based on BeanFactory, the function of obtaining the parent BeanFactory is added
  • DefaultSingletonBeanRegistry:It is a class , implements the SingletonBeanRegistry interface, and has the function of directly registering and obtaining a singletonBean
  • ConfigurableBeanFactory:On the basis of HierarchicalBeanFactory and SingletonBeanRegistry, settings are added Parent BeanFactory, class loader (indicating that a class loader can be specified to load classes), setting the Spring EL expression parser (indicating that the BeanFactory can parse EL expressions), and setting type conversion services (indicating that the BeanFactory can perform type Conversion), you can add BeanPostProcessor (indicating that the BeanFactory supports Bean's post-processor), you can merge BeanDefinition, you can destroy a Bean and other functions
  • FactoryBeanRegistrySupport: Supports the functions of FactoryBean
  • AutowireCapableBeanFactory: It directly inherits BeanFactory. Based on BeanFactory, it supports automatic assembly of Bean during the process of creating Bean.
  • AbstractBeanFactory: Implements ConfigurableBeanFactory The interface inherits FactoryBeanRegistrySupport. The functions of this BeanFactory are very comprehensive, but it cannot automatically assemble and obtain beanNames
  • ConfigurableListableBeanFactory:Inherits ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactoryAbstract
  • AutowireCapableBeanFactory: Inherits AbstractBeanFactory, implements AutowireCapableBeanFactory, and has the function of automatic assembly
  • DefaultListableBeanFactory: Inherits AbstractAutowireCapableBeanFactory, implements ConfigurableListableBeanFactory interface and BeanDefinitionRegistry interface, so DefaultListableBeanFactory The function is very powerful

ApplicationContext

ApplicationContext is an interface, and it is actually a BeanFactory, but it is more powerful than BeanFactory, such as:

  • HierarchicalBeanFactory: Has the function of getting the parent BeanFactory
  • ListableBeanFactory:Has the function of getting the beanNames
  • ResourcePatternResolver:Resource Loader, which can obtain multiple resources (file resources, etc.) at one time
  • EnvironmentCapable: Can obtain the runtime environment (there is no function to set the runtime environment)
  • ApplicationEventPublisher: Has the function of broadcasting events (no function of adding event listeners)
  • MessageSource: Has internationalization function

ApplicationContext has two important implementation classes:

  • AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext

AnnotationConfigApplicationContext

Detailed analysis of the life cycle of beans created by java Spring

  • ConfigurableApplicationContext:继承了ApplicationContext接口,增加了 添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能
  • AbstractApplicationContext:实现了ConfigurableApplicationContext接口
  • GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
  • AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的**@Configuration注解**,已经可以处理**@Bean注解**),同时可以扫描
  • AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能

ClassPathXmlApplicationContext

Detailed analysis of the life cycle of beans created by java Spring

它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition

资源加载

ApplicationContext还拥有资源加载的功能,比如,可以直接利用ApplicationContext获取某个文件的内容:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        Resource resource = context.getResource("file:/Users/xiexu/Library/Mobile Documents/com~apple~CloudDocs/SSM/day01/src/main/java/cn/xx/domain/User.java");
        System.out.println(resource.contentLength());

        Resource resource1 = context.getResource("https://www.baidu.com");
        System.out.println(resource1.contentLength());
        System.out.println(resource1.getURL());

        Resource resource2 = context.getResource("classpath:spring.xml");
        System.out.println(resource2.contentLength());
        System.out.println(resource2.getURL());

				// 可以一次性获取多个
        Resource[] resources = context.getResources("classpath:cn/xx/domain/*.class");
        for (Resource resource3 : resources) {
            System.out.println(resource3.contentLength());
            System.out.println(resource3.getFilename());
        }
Copy after login

事件发布

先定义一个事件监听器:

		@Bean
    public ApplicationListener applicationListener() {
        return new ApplicationListener() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("接收到了一个事件");
            }
        };
    }
Copy after login

然后发布一个事件:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        context.publishEvent("kkk");
Copy after login

类型转化

在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。

PropertyEditor

这其实是JDK中提供的类型转化工具

public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        User user = new User();
        user.setName(text);
        this.setValue(user);
    }

}
Copy after login
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
propertyEditor.setAsText("1");
User value = (User) propertyEditor.getValue();
System.out.println(value);
Copy after login

在Spring容器中注册 PropertyEditor:

		@Bean
    public CustomEditorConfigurer customEditorConfigurer() {
        CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
        Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();

        /**
         * 表示StringToUserPropertyEditor可以将String转化成User类型,
         * 在Spring源码中,如果发现当前对象是String,而需要的类型是User,
         * 就会使用该PropertyEditor来做类型转化
         */
        propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
        customEditorConfigurer.setCustomEditors(propertyEditorMap);
        return customEditorConfigurer;
    }
Copy after login

假设现在有如下 Bean:

@Component
public class Test {

    @Value("xiaoming")
    private User user;

    public void test() {
        System.out.println(user);
        System.out.println(user.getName());
    }
}
Copy after login

Detailed analysis of the life cycle of beans created by java Spring-20220906213724892

ConversionService

Spring中提供的类型转化服务,它比PropertyEditor更强大

public class StringToUserConverter implements ConditionalGenericConverter {

    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, User.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        User user = new User();
        user.setName((String) source);
        return user;
    }

}
Copy after login
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User value = conversionService.convert("1", User.class);
System.out.println(value);
Copy after login

在Spring中注册ConversionService:

		@Bean
    public ConversionServiceFactoryBean conversionService() {
        ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
        conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));

        return conversionServiceFactoryBean;
    }
Copy after login

TypeConverter

整合了PropertyEditor和ConversionService的功能,是Spring内部用的:

SimpleTypeConverter typeConverter = new SimpleTypeConverter();
        typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
        User value = typeConverter.convertIfNecessary("xxx", User.class);
        System.out.println(value);
        System.out.println(value.getName());
Copy after login
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
        DefaultConversionService conversionService = new DefaultConversionService();
        conversionService.addConverter(new StringToUserConverter());
        typeConverter.setConversionService(conversionService);
        User value = typeConverter.convertIfNecessary("xxx", User.class);
        System.out.println(value);
        System.out.println(value.getName());
Copy after login

OrderComparator

OrderComparator是Spring所提供的一种比较器,可以根据@Order注解或实现Ordered接口来进行值的比较,从而可以进行排序。

public class A implements Ordered {

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

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }
}
Copy after login
public class B implements Ordered {

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

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }
}
Copy after login
public class Main {

    public static void main(String[] args) {
        A a = new A(); // order=3
        B b = new B(); // order=2

        OrderComparator comparator = new OrderComparator();
        System.out.println(comparator.compare(a, b));  // 1

        List list = new ArrayList<>();
        list.add(a);
        list.add(b);

        // 按order值升序排序
        list.sort(comparator);

        System.out.println(list);  // B,A
    }

}
Copy after login

另外,Spring中还提供了一个OrderComparator的子类:AnnotationAwareOrderComparator,它支持用@Order来指定order值。

比如:

@Order(3)
public class A {

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }

}
Copy after login
@Order(2)
public class B {

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }

}
Copy after login
public class Main {

    public static void main(String[] args) {
        A a = new A(); // order=3
        B b = new B(); // order=2

        AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
        System.out.println(comparator.compare(a, b)); // 1

        List list = new ArrayList<>();
        list.add(a);
        list.add(b);

        // 按order值升序排序
        list.sort(comparator);

        System.out.println(list); // B,A
    }

}
Copy after login

BeanPostProcessor

BeanPostProcess 表示Bean的后置处理器,我们可以定义一个或多个BeanPostProcessor

@Component
public class XiexuBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("初始化前");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("初始化后");
        }
        return bean;
    }

}
Copy after login

一个BeanPostProcessor可以在任意一个Bean初始化前以及初始化后去额外的做一些用户自定义的逻辑,当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean)。

我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。

BeanFactoryPostProcessor

BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。

比如,我们可以这样定义一个BeanFactoryPostProcessor:

@Component
public class XiexuBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("加工beanFactory");
    }
}
Copy after login

可以在postProcessBeanFactory()方法中对BeanFactory进行加工。

FactoryBean

上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们自己来创造,也是可以的,比如通过FactoryBean:

@Component
public class XiexuFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        User user = new User();

        return user;
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}
Copy after login

通过上面这段代码,我们自己创造了一个User对象,并且它将成为Bean。但是通过这种方式创造出来的User的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。

注意:单例池里面还是原来的xiexuFactoryBean,而通过getObject()方法返回的userBean是存放在factoryBeanObjectCache里面(缓存)。

Detailed analysis of the life cycle of beans created by java Spring-20220907162114007

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        // 如果beanName加上&,表示获取的是单例池里面的XiexuFactoryBean
        Object bean1 = context.getBean("&xiexuFactoryBean");
        System.out.println(bean1); // cn.xx.domain.XiexuFactoryBean@2de8284b

        // 如果beanName没有加上&,表示获取的是factoryBeanObjectCache缓存里面的userBean
        Object bean2 = context.getBean("xiexuFactoryBean");
        System.out.println(bean2); // cn.xx.domain.User@396e2f39
Copy after login

有同学可能会想到,通过@Bean也可以自己生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?其实在很多场景下他俩是可以替换的,但是站在原理层面来说,区别也很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。

ExcludeFilter 和 IncludeFilter

这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter 表示排除过滤器IncludeFilter 表示包含过滤器

比如以下配置,表示扫描cn.xx这个包下面的所有类,但是排除UserService类,

就算UserService类上面有@Component注解也不会成为Bean。

@ComponentScan(value = "cn.xx", 
        excludeFilters = {@ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE, 
                classes = UserService.class)})
public class AppConfig {
}
Copy after login

再比如以下配置,就算UserService类上没有@Component注解,它也会被扫描成为一个Bean。

@ComponentScan(value = "cn.xx",
        includeFilters = {@ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                classes = UserService.class)})
public class AppConfig {
}
Copy after login

FilterType分为:

  • ANNOTATION:表示是否包含某个注解
  • ASSIGNABLE_TYPE:表示是否是某个类
  • ASPECTJ:表示是否符合某个Aspectj表达式
  • REGEX:表示是否符合某个正则表达式
  • CUSTOM:自定义

在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilterincludeFilters,表示默认情况下在Spring扫描过程中会认为类上有@Component注解的就是Bean。

MetadataReader、ClassMetadata、AnnotationMetadata

在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。

MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。比如:

public class Test {

    public static void main(String[] args) throws IOException {
        SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();

        // 构造一个MetadataReader
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("cn.xx.service.impl.UserServiceImpl");

        // 得到一个ClassMetadata,并获取了类名
        ClassMetadata classMetadata = metadataReader.getClassMetadata();

        System.out.println(classMetadata.getClassName());

        // 获取一个AnnotationMetadata,并获取类上的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        for (String annotationType : annotationMetadata.getAnnotationTypes()) {
            System.out.println(annotationType);
        }
    }
}
Copy after login

5.Spring之Bean生命周期源码解析

Spring 扫描底层流程(doScan方法)

  • 扫描包路径,得到包路径下的所有class文件对象(注意,这里不是指Class对象,而是文件对象,可以理解为File对象)
  • 利用ASM技术解析每个class文件对象,得到class元数据信息
  • 如果当前类和某个excludeFilter匹配,那就排除这个类;如果当前类和某个includeFilter匹配,那就获取这个类(默认情况下,Spring会有一个@Component注解的includeFilter)
  • 进一步进行条件注解@Conditional的匹配筛选
  • 都匹配成功后,根据当前类生成一个ScannedGenericBeanDefinition
  • 然后判断如果该类不是顶级类或者静态内部类,则不通过;如果该类是抽象类或者接口类,则不通过;如果该类是抽象类并且该类中有@Lookup注解的方法,则通过。
  • 最终扫描到某些BeanDefinition
  • 遍历每个BeanDefinition,解析每个类的@Scope内容并设置到对应的BeanDefinition中
  • 设置AnnotationBeanNameGenerator生成beanName(解析@Component注解所指定的beanName,如果没有指定则默认生成「该类名字的第一个字母小写」;如果该类的前两个字母都是大写,则beanName就是该类的名字)
  • 给BeanDefinition对象中的属性赋默认值
  • 解析@Lazy@Primary@DependsOn@Role@Description 等注解并赋值给BeanDefinition对应的属性
  • 判断当前beanName是否存在Spring容器中,如果不存在则把beanName和BeanDefinition注册到Spring容器中(也就是存入beanDefinitionMap);如果存在则会有两种方案:
    • 如果已经存在的BeanDefinition对应的类型和扫描到的BeanDefinition对应的类型相同的话(兼容),则直接返回false而不会抛出异常。
    • 如果已经存在的BeanDefinition对应的类型和扫描到的BeanDefinition对应的类型不相同的话(不兼容),则会报错并抛出异常。
  • 扫描结束。

生成BeanDefinition

  • 首先通过ResourcePatternResolver获得指定包路径下的所有.class文件(Spring源码中将此文件包装成了Resource对象)
  • 遍历每个Resource对象利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory,MetadataReader的具体实现类为SimpleMetadataReader)
  • 利用MetadataReader进行excludeFiltersincludeFilters,以及条件注解@Conditional的筛选(某个类上是否存在@Conditional注解,如果存在则调用注解中所指定的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉)
  • 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition再基于metadataReader判断对应的类是不是接口或抽象类
  • 如果筛选通过,就表示扫描到了一个Bean,将ScannedGenericBeanDefinition加入结果集

注意:

上面说的是通过扫描得到BeanDefinition对象,我们还可以通过直接定义BeanDefinition,或解析spring.xml文件的<bean>,或者@Bean注解得到BeanDefinition对象。

MetadataReader 表示类的元数据读取器,主要包含了一个AnnotationMetadata,功能有

  • 获取类的名字
  • 获取父类的名字
  • 获取所实现的所有接口名
  • 获取所有内部类的名字
  • 判断是不是抽象类
  • 判断是不是接口
  • 判断是不是一个注解
  • 获取拥有某个注解的方法集合
  • 获取类上添加的所有注解信息
  • 获取类上添加的所有注解类型集合

注意:

CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是利用 ASM 技术,并没有加载这个类到JVM中。并且最终得到的ScannedGenericBeanDefinition对象,它的 beanClass 属性存储的是当前类的名字,而不是class对象。(beanClass属性的类型是Object,它即可以存储类的名字,也可以存储类对象)

合并BeanDefinition

通过扫描得到所有的BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了。在Spring中支持父子BeanDefinition,和Java子父类类似。

父子BeanDefinition实际上用得比较少,例如:这么定义的情况下,child是单例Bean。

<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>
Copy after login

但如果是下面这样,child就是原型Bean了。

<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="parent"/>
Copy after login

因为child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性。

所以在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,才能得到完整的child的BeanDefinition。

加载类

BeanDefinition合并之后,就可以去创建Bean对象了,而创建Bean就必须实例化对象,而实例化就必须先加载当前BeanDefinition所对应的class,在AbstractAutowireCapableBeanFactory类的createBean()方法中,一开始就会调用:

Detailed analysis of the life cycle of beans created by java Spring-20220926221933600

Detailed analysis of the life cycle of beans created by java Spring-20220926222050533

public boolean hasBeanClass() {
		// 判断当前BeanDefinition的beanClass属性,是不是Class类型
		return (this.beanClass instanceof Class);
	}
Copy after login

如果beanClass属性的类型是Class,那么就直接返回;如果不是,则会根据类名进行加载(doResolveBeanClass方法所做的事情)

Detailed analysis of the life cycle of beans created by java Spring-20220926223604150

	@Override
	@Nullable
	public ClassLoader getBeanClassLoader() {
		return this.beanClassLoader;
	}

	@Nullable
	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
Copy after login

先利用BeanFactory所设置的类加载器来加载类,如果没有设置,则默认使用ClassUtils.getDefaultClassLoader()所返回的类加载器来进行加载。

/** * 获取默认的类加载器 */@Nullablepublic static ClassLoader getDefaultClassLoader() {ClassLoader cl = null;/** * 优先获取线程中的类加载器 * 一开始,tomcat会将自定义的类加载器设置到线程上下文中, * 然后当你走到这一步的时候,就可以获取到线程中的tomcat自定义类加载器 */try {cl = Thread.currentThread().getContextClassLoader();} catch (Throwable ex) {}// 如果线程上下文中的类加载器为空,那就获取ClassUtils类所对应的类加载器if (cl == null) {cl = ClassUtils.class.getClassLoader();if (cl == null) { // 如果类加载器等于null,就说明是引导类加载器// ClassUtils类是被Bootstrap类加载器加载的,则获取系统类加载器try {cl = ClassLoader.getSystemClassLoader();} catch (Throwable ex) {}}}// 返回类加载器return cl;}
Copy after login

ClassUtils.getDefaultClassLoader()

优先返回当前线程中的类加载器如果当前线程中的类加载器为空,则返回ClassUtils类的类加载器如果ClassUtils类的类加载器为空,那么表示是Bootstrap类加载器加载的ClassUtils类,那么则返回系统类加载器 4.实例化前

当前BeanDefinition对应的类加载成功后,就可以实例化对象了,但是…

在实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某些Bean实例化之前做一些启动动作。

Detailed analysis of the life cycle of beans created by java Spring-20220926231603057

Detailed analysis of the life cycle of beans created by java Spring-20220926232155295

Detailed analysis of the life cycle of beans created by java Spring-20220926232420898

这个扩展点叫InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation( )。比如:

@Componentpublic class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {    if ("userService".equals(beanName)) {     System.out.println("实例化前");    }    return null;  }  }
Copy after login

以上代码会导致,在userService这个Bean实例化前,会进行打印。

注意:postProcessBeforeInstantiation()是有返回值的,如果这么实现:

@Componentpublic class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {    if ("userService".equals(beanName)) {     System.out.println("实例化前");     return new UserService();    }  return null; }  }
Copy after login

userService这个Bean在实例化前会直接返回一个由我们所定义的UserService对象。如果是这样,表示不需要Spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后这一步。

5.实例化

在这个步骤中就会根据BeanDefinition去创建一个对象了。

6.BeanDefinition的后置处理

Detailed analysis of the life cycle of beans created by java Spring-20220926234536686

Bean对象实例化之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又提供了一个扩展点MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition( ),可以对此时的BeanDefinition进行加工,比如:

@Componentpublic class ZhouyuMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor { @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {  if ("userService".equals(beanName)) {   beanDefinition.getPropertyValues().add("orderService", new OrderService()); // 注入属性  } }  }
Copy after login

在Spring源码中,AutowiredAnnotationBeanPostProcessor 就是一个MergedBeanDefinitionPostProcessor,它的postProcessMergedBeanDefinition()方法中会去查找注入点,并缓存在AutowiredAnnotationBeanPostProcessor对象的一个Map中(injectionMetadataCache)。

7.实例化后

Detailed analysis of the life cycle of beans created by java Spring-20220927001402231

Detailed analysis of the life cycle of beans created by java Spring-20220927001432634

在处理完BeanDefinition后,Spring又设计了一个扩展点:InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation( ),比如:

@Componentpublic class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {  if ("userService".equals(beanName)) {   UserService userService = (UserService) bean;   userService.test();  }  return true; }}
Copy after login

上述代码就是对userService所实例化出来的对象进行处理。

注意:这个扩展点在Spring源码中基本没有怎么使用。

8.自动注入 9.处理属性

Detailed analysis of the life cycle of beans created by java Spring-20220927002120020

/** * 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值 * AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了 * 并不会处理pvs指的是: * 如果当前bean的某些属性已经通过postProcessMergedBeanDefinition方法注入了,那么该属性上面的@Autowired注解应该是无效的, * 因为程序员已经将自定义的值设置到属性里面去了 */
Copy after login

这个步骤中,就会处理@Autowired@Resource@Value等注解,也是通过**InstantiationAwareBeanPostProcessor.postProcessProperties( )**扩展点来实现的。

比如:我们甚至可以实现一个自己的自动注入功能

@Componentpublic class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {for (Field field : bean.getClass().getFields()) {if (field.isAnnotationPresent(ZhouyuInject.class)) {field.setAccessible(true);try {field.set(bean, "123");} catch (IllegalAccessException e) {e.printStackTrace();}}}}return pvs;}}
Copy after login

10.执行Aware

Detailed analysis of the life cycle of beans created by java Spring-20220927003155088

Detailed analysis of the life cycle of beans created by java Spring-20220927003137255

完成了属性赋值之后,Spring会执行一些回调,包括:

BeanNameAware:回传beanName给bean对象BeanClassLoaderAware:回传classLoader给bean对象BeanFactoryAware:回传beanFactory给对象 11.初始化前

Detailed analysis of the life cycle of beans created by java Spring-20220927003420161

Detailed analysis of the life cycle of beans created by java Spring-20220927003447488

初始化前,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessBeforeInitialization( ),比如:

@Componentpublic class ZhouyuBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  if ("userService".equals(beanName)) {   System.out.println("初始化前");  }  return bean; }}
Copy after login

利用初始化前,可以对已经进行了依赖注入的Bean进行处理。

在Spring源码中:

InitDestroyAnnotationBeanPostProcessor 会在初始化前这个步骤中执行@PostConstruct的方法,ApplicationContextAwareProcessor 会在初始化前这个步骤中进行其他Aware的回调: EnvironmentAware:回传环境变量EmbeddedValueResolverAware:回传占位符解析器ResourceLoaderAware:回传资源加载器ApplicationEventPublisherAware:回传事件发布器MessageSourceAware:回传国际化资源ApplicationStartupAware:回传应用其他监听对象,可忽略ApplicationContextAware:回传Spring容器ApplicationContext 12.初始化

Detailed analysis of the life cycle of beans created by java Spring-20220927003759721

Detailed analysis of the life cycle of beans created by java Spring-20220927003907501

查看当前Bean对象是否实现了InitializingBean接口,如果实现了就调用其afterPropertiesSet()方法执行BeanDefinition中指定的初始化方法 13.初始化后

Detailed analysis of the life cycle of beans created by java Spring-20220927004002073

Detailed analysis of the life cycle of beans created by java Spring-20220927004022427

这是Bean创建生命周期中的最后一个步骤,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessAfterInitialization( ),比如:

@Componentpublic class ZhouyuBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  if ("userService".equals(beanName)) {   System.out.println("初始化后");  }  return bean; }}
Copy after login

可以在这个步骤中,对Bean进行最终处理,Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的Bean对象

14.总结BeanPostProcessor

实例化前:

InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()

实例化

MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()

实例化后:

InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()

自动注入

InstantiationAwareBeanPostProcessor.postProcessProperties()

Aware对象

初始化前:

BeanPostProcessor.postProcessBeforeInitialization()

初始化

初始化后:

BeanPostProcessor.postProcessAfterInitialization()

Detailed analysis of the life cycle of beans created by java Spring-20220927004746839

推荐学习:《java视频教程

The above is the detailed content of Detailed analysis of the life cycle of beans created by java Spring. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:jb51.net
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template