spring 5.0.8
Latest 5.2.4
Annotated version
You can refer to: https://www.cnblogs.com/leeSmall/p/10099503.html
AnnotationConfigApplicationContext actx
=new AnnotationConfigApplicationContext(Config.class);
HelloWorld helloWorld = actx.getBean(HelloWorld.class);
helloWorld.sayHello("hello");
Class diagram
Initialization process analysis
AnnotationConfigApplicationContext
It can be seen that a static code block is called first:
static {
// Eagerly load the ContextClosedEvent class to avoid weird classloader issues
// on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
//就把这个注释翻译以下呗 就是说要饿汉式的加载关闭事件去防止奇怪的类加载器事件在应用关闭的时候
ContextClosedEvent.class.getName();
}
Then take a look at chanting, what is this ContextClosedEvent? But we beginners, we do n’t understand it?
What is the role of ContextClosedEvent?
It can be seen that it belongs to the category of event monitoring, and it is not deep here.It is estimated that the corresponding event is triggered for now; continue to look at the construction method of AnnotationConfigApplicationContext:
//根据参数类型可以知道,其实可以传入多个annotatedClasses,但是这种情况出现的比较少
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//调用无参构造函数,会先调用父类GenericApplicationContext的构造函数
//父类的构造函数里面就是初始化DefaultListableBeanFactory,并且赋值给beanFactory
//本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,一个扫描器ClassPathBeanDefinitionScanner scanner
//scanner的用处不是很大,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
this();
//把传入的类进行注册,这里有两个情况,
//传入传统的配置类
//传入bean(虽然一般没有人会这么做
//看到后面会知道spring把传统的带上@Configuration的配置类称之为FULL配置类,不带@Configuration的称之为Lite配置类
//但是我们这里先把带上@Configuration的配置类称之为传统配置类,不带的称之为普通bean
register(annotatedClasses);
//刷新
refresh();
}
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
//注解bean定义读取器,主要作用是用来读取被注解的了bean
private final AnnotatedBeanDefinitionReader reader;
//扫描器,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
//this
public AnnotationConfigApplicationContext() {
//会隐式调用父类的构造方法,初始化DefaultListableBeanFactory
//初始化一个Bean读取器
this.reader = new AnnotatedBeanDefinitionReader(this);
//初始化一个扫描器,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
}
this()
This is a parameterized construction method that can receive multiple configuration classes, but in general, only one configuration class will be passed in.
There are two cases for this configuration class, one is a configuration class with @Configuration annotation in the traditional sense, and the other is without @Configuration but with @Component, @Import, @ImportResouce, @Service, @ The annotated configuration classes such as ComponentScan internally call the former the Full configuration class and the latter the Lite configuration class. In some places, Lite configuration classes are also called ordinary beans.
The AnnotationConfigApplicationContext class has an inheritance relationship and will implicitly call the constructor of the parent class:
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
public GenericApplicationContext() {
//就是初始化了一个DefaultListableBeanFactory
this.beanFactory = new DefaultListableBeanFactory();
}
}
DefaultListableBeanFactory is quite important, it can be seen from the literal meaning that it is a Bean factory, what is a Bean factory? Of course, it is used to produce and obtain Bean.
Then look at:
##AnnotatedBeanDefinitionReader
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
Then enter AnnotationConfigUtils
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
This is another facade method, click again, the return value of this method is Set, but the upstream method does not receive this return value, so the return value of this method is not very important, of course, the method is also assigned to this return value Not important anymore. Since this method has more content, the core is posted here. The core of this method is to register multiple Beans built in Spring:
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
Determine if ConfigurationClassPostProcessorBean already exists in the container
If it does not exist (of course, it certainly does not exist here), then obtain the BeanDefinition of ConfigurationClassPostProcessor through the construction method of RootBeanDefinition, which is a subclass of BeanDefinition:
[External chain image transfer failed, the source site may have an anti-theft chain mechanism, it is recommended to save the image and upload it directly
Of course, registering other beans here is the same process.
What is BeanDefinition, as the name suggests, it is used to describe Bean, which contains a series of information about Bean, such as the scope of Bean, the class corresponding to Bean, whether it is lazy loaded, whether it is Primary, etc. This BeanDefinition is also very important , We will often deal with it in the future.
registerPostProcessor method:
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
This method sets a Role for BeanDefinition, ROLE_INFRASTRUCTURE means that this is internal to spring, not user-defined, and then call the registerBeanDefinition method, then click in, Oh No, you will find that it is an interface, there is no way to directly click in First, we must know what the registry implementation class is, so what is its implementation? The answer is DefaultListableBeanFactory:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
This is another facade method, click it again, the core lies in the following two lines of code:
//beanDefinitionMap是Map<String, BeanDefinition>,
//这里就是把beanName作为key,ScopedProxyMode作为value,推到map里面
this.beanDefinitionMap.put(beanName, beanDefinition);
//beanDefinitionNames就是一个List<String>,这里就是把beanName放到List中去
this.beanDefinitionNames.add(beanName);
It can be seen from here that DefaultListableBeanFactory is what we call a container, which contains beanDefinitionMap, beanDefinitionNames, beanDefinitionMap is a hashMap, beanName as Key, beanDefinition as Value, beanDefinitionNames is a collection, which stores beanName. Make a breakpoint and run here for the first time to monitor these two variables:
The beanDefinitionMap and beanDefinitionNames in the DefaultListableBeanFactory are also very important. You will often see it in the future. It is best to see it. The first time you can reflect what data is placed in it
This is just a registration, it can be simply understood as putting some raw materials into the factory, the factory has not really produced.
As mentioned above, there will be several Beans registered in a series. The most important one (no one) is BeanDefinitionRegistryPostProcessor Bean.
ConfigurationClassPostProcessor implements the BeanDefinitionRegistryPostProcessor interface. The BeanDefinitionRegistryPostProcessor interface extends the BeanFactoryPostProcessor interface. BeanFactoryPostProcessor is one of Spring's extension points. ConfigurationClassPostProcessor is a very important class of Spring. You must firmly remember the class and its inheritance relationship mentioned above.
The BeanPostProcessor interface is also one of Spring's extension points.
At this point, the analysis of the instantiated AnnotatedBeanDefinitionReader reader is completed.
register()
Return to the beginning, and then analyze the second line of code:
register(annotatedClasses);
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
//AnnotatedGenericBeanDefinition可以理解为一种数据结构,是用来描述Bean的,这里的作用就是把传入的标记了注解的类
//转为AnnotatedGenericBeanDefinition数据结构,里面有一个getMetadata方法,可以拿到类上的注解
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//判断是否需要跳过注解,spring中有一个@Condition注解,当不满足条件,这个bean就不会被解析
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
//解析bean的作用域,如果没有设置的话,默认为单例
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
//获得beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//解析通用注解,填充到AnnotatedGenericBeanDefinition,解析的注解为Lazy,Primary,DependsOn,Role,Description
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
//限定符处理,不是特指@Qualifier注解,也有可能是Primary,或者是Lazy,或者是其他(理论上是任何注解,这里没有判断注解的有效性),如果我们在外面,以类似这种
//AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);常规方式去初始化spring,
//qualifiers永远都是空的,包括上面的name和instanceSupplier都是同样的道理
//但是spring提供了其他方式去注册bean,就可能会传入了
if (qualifiers != null) {
//可以传入qualifier数组,所以需要循环处理
for (Class<? extends Annotation> qualifier : qualifiers) {
//Primary注解优先
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
//Lazy注解
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
//其他,AnnotatedGenericBeanDefinition有个Map<String,AutowireCandidateQualifier>属性,直接push进去
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
//这个方法用处不大,就是把AnnotatedGenericBeanDefinition数据结构和beanName封装到一个对象中
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//注册,最终会调用DefaultListableBeanFactory中的registerBeanDefinition方法去注册,
//DefaultListableBeanFactory维护着一系列信息,比如beanDefinitionNames,beanDefinitionMap
//beanDefinitionNames是一个List<String>,用来保存beanName
//beanDefinitionMap是一个Map,用来保存beanName和beanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
Here again, we need to register the configuration class in the usual way. In this method, except for the first parameter, the other parameters are the default values.
-
Through the construction method of AnnotatedGenericBeanDefinition, get the BeanDefinition of the configuration class. Is it seem similar here? When registering the ConfigurationClassPostProcessor class, the BeanDefinition is also obtained through the construction method, but then it was obtained through RootBeanDefinition, now it is obtained through AnnotatedGenericBeanDefinition .
-
To determine whether to skip registration, Spring has a @Condition annotation. If the conditions are not met, the registration of this class will be skipped.
-
Then there is the resolution scope, if not set, the default is a singleton.
-
Get BeanName.
-
Analyze the common annotations and fill them into AnnotatedGenericBeanDefinition. The annotated annotations are Lazy, Primary, DependsOn, Role, and Description.
-
The qualifier processing is not specific to @Qualifier annotation, it may also be Primary, or Lazy, or other (in theory, any annotation, there is no judgment on the validity of the annotation).
-
Encapsulate the AnnotatedGenericBeanDefinition data structure and beanName into an object (this is not very important, it can be simply understood as a convenient parameter).
-
Registration, will eventually call the registerBeanDefinition method in DefaultListableBeanFactory to register:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { //获取beanName // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); //注册bean registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); //Spring支持别名 // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
Does this registerBeanDefinition have a similar feeling again? Yes, this method has already been parsed when registering the Bean built in Spring above, and it will not be repeated here. At this time, let us observe the beanDefinitionMap beanDefinitionNames two. Variables, in addition to the Bean built in Spring, and the Bean we passed in, the Bean here is of course our configuration class;
The registration configuration class is also analyzed here.
You can see that in fact, Spring has not yet scanned, but just instantiated a factory, registered some built-in Bean and the configuration class we passed in. The real big head is in the third line of code;
##refresh()
https://www.cnblogs.com/leeSmall/p/10188408.html
Process flow of org.springframework.context.support.AbstractApplicationContext.refresh () method
d) Create instance process when getBean () in beanfactory
BeanFactoryPostProcessor processes the BeanFactory before instantiating the bean.
After the bean is instantiated, the
two classes that process the bean use the observer pattern
AbstractApplicationContextrefresh template method pattern
execution priority: priorityOrded> orded
Bean life cycle
https://www.jianshu.com/p/00b29d8681ca
BeanDefinition
https://www.cnblogs.com/leeSmall/p/10134307.html
Dependency injection DI
https://www.cnblogs.com/leeSmall/p/10228771.html
How to deal with property circular dependency?
a) Bean1 and Bean2 are singleton beans.
Cyclic dependence is successful.
B) Bean1 and Bean2 are singletons and one is prototype.
Cyclic dependence is successful
c) Both Bean1 and Bean2 are prototypes
Cyclic dependence is unsuccessful
3) Thinking: Why can't two cycles depend on the prototype, but the single case can?
The attribute of a Bean depends on another bean instance. Is the injection process just getBean () from the BeanFactory and assign it to the attribute?
Yes, first get the dependent beans from the Bean factory, create it if not
So why is a singleton possible, but not a prototype?
According to the above logic, then you can use getBean () to obtain the dependent bean instance in the singleton, but not in the prototype. Why?
Think again about the difference between singleton and prototype beans in BeanFactory:
Singleton beans are cached in BeanFactory, while prototype beans are not cached.
What is the difference between cached and uncached handling of circular dependencies?
Consider the process of creating a Bean instance:
first Bean1, create an instance of Bean1-> then perform dependency injection processing on its properties-> depend on Bean2, from BeanFactorygetBean ("bean2")-> create an instance of Bean2-> right The properties of the Bean2 instance are subjected to dependency injection processing-> Depend on Bean1, the cache of the Bean1 instance obtained from the BeanFactory
can get the previous Bean instance through the beanFactory's getBean (). If it is not cached, when the bean2 instance dependency is injected into Bean1, another instance of Bean1 will be created from BeanFactorygetBean (), which will create an infinite loop dependency.
Think again, is there a requirement for caching of singleton beans?
Yes, it must be cached (exposed) to the BeanFactory before the attribute dependency injection process.
If there are multiple constructors with parameters and each constructor has a property to be injected in the parameter list, where will userDaoJdbc be injected?
Result: It will be injected into the construction method with only one parameter, and which construction method is injected after testing has no relation to the order of the construction methods
Question 2: If there is only one constructor, but there are two parameters, one is the parameter to be injected, and the other is the other type of parameter, can this injection be successful?
Result: Failure, even if the parameter name userDao to be injected is specified in the costract-arg tag through the name attribute, it will fail.
Question 3: If we want to inject values into the construction method with multiple parameters, how should we write them in the configuration file?
Reference writing: Specify the value to be injected through the name attribute, regardless of the order of the parameter list of the construction method.
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
<constructor-arg name="userDao" ref="userDaoJdbc"></constructor-arg>
<constructor-arg name="user" ref="user"></constructor-arg>
</bean>
<!-- 注册实体User类,用于测试 -->
<bean id="user" class="com.lyu.spring.entity.User"></bean>
<!-- 注册jdbc实现的dao -->
<bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>
Question 4: If there are multiple construction methods, and each construction method only has a different order of parameters, which one will be injected into the multiple parameters through the construction method?
Result: Which construction method is injected first, in this case depends on the order of the construction methods.
setter injection
Spring converts the first letter of each word of the name value to uppercase, and then stitches "set" on the front to form a method name, and then finds the method in the corresponding class and calls it through reflection to achieve injection.
Remember: the name attribute value has nothing to do with the name of the member variable in the class and the parameter name of the set method, only the name of the corresponding set method
springaop
https://www.cnblogs.com/leeSmall/p/10236553.html
Aspect=Advice+Pointcut
Where are the aspects of AspectJ annotations read and loaded?
Possible places:
BeanDefinitionRegistryPostProcessor x
BeanFactoryPostProcessor x
InstantiationAwareBeanPostProcessor Bean instance before and after creation
BeanPostProcessor
Xml method analysis:
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator
annotation method analysis:
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
relationship between the two:
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()
a) Where do weave in?
In org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors (), hit a breakpoint to get the call stack
Entrance:
com.study.leesmall.spring.sample.aop.AopMainUseAspectAnnotation
b) How to judge whether the bean is created or not? How to exclude advice Bean?
Exclude advice Bean:
Skip advice bean Skip yourself with @Aspect annotation, you cannot create a proxy for yourself, otherwise you enter an infinite loop, such as AspectAdviceBeanUseAnnotation
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(Class<?>, String)
c) How to choose jdk dynamic proxy or cglib dynamic proxy
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(Class<?>, String, Object[], TargetSource)
org.springframework.aop.framework.ProxyFactory.getProxy(ClassLoader)
org.springframework.aop.framework.ProxyCreatorSupport.createAopProxy()
org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(AdvisedSupport)
d) How to create an agent, which classes are involved, and how to collaborate.
AutoProxyCreator
ProxyConfig ProcxyFactory
AopProxyFactory
AopProxy
a) How to determine the advice of the current method in the agency?
Pointcut matching in the called Advisor
b) How to organize multiple advice execution?
Chain of responsibility model
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(Object, Method, Object[])
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
Transaction management
https://www.cnblogs.com/leeSmall/p/10306672.html
@EnableTransactionManagement
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- 配置初始化大小、最小、最大连接数 -->
<property name="initialSize" value="1" />
<property name="minIdle" value="1" />
<property name="maxActive" value="10" />
</bean>
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- ********************** 声明式事务配置 begin ************** -->
<!-- 配置事务增强的advice -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" />
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!-- 配置事务的AOP切面 -->
<aop:config>
<aop:pointcut id="allService" expression="execution(* com.study.leesmall.spring.sample.tx.service.*Service.*(..)))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allService"/>
</aop:config>