In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces "how to understand container DefaultListableBeanFactory". In daily operation, I believe many people have doubts about how to understand container DefaultListableBeanFactory. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the doubts about "how to understand container DefaultListableBeanFactory". Next, please follow the editor to study!
1.DefaultListableBeanFactory
To say XmlBeanFactory, you have to talk about its parent class, DefaultListableBeanFactory, because most of the functionality in XmlBeanFactory is actually provided in DefaultListableBeanFactory, and XmlBeanFactory just makes some customizations to read the IO stream.
DefaultListableBeanFactory is a complete and mature IoC container, if your requirements are very simple, you can even use DefaultListableBeanFactory directly, if your requirements are more complex, then you can also achieve it by extending the functions of DefaultListableBeanFactory, it can be said that DefaultListableBeanFactory is the ancestor of the entire Spring IoC container.
Let's first take a look at DefaultListableBeanFactory's inheritance relationship:
As you can see from the class diagram, DefaultListableBeanFactory is actually an aggregator. In Spring, there are different interfaces for different operations of Bean, each interface has its own corresponding implementation, and finally all the implementations are gathered together in DefaultListableBeanFactory. From this class inheritance diagram, we can probably feel how powerful the class design is in Spring, and the code coupling is very low.
Most of these classes will be covered later in this series. Now let me briefly introduce the role of each class. Let's get acquainted with each other:
BeanFactory: this API can tell from the name that it is a factory of Bean. The BeanFactory interface defines various methods to obtain Bean, determine whether Bean exists, determine whether Bean is singleton, and other basic methods for Bean.
ListableBeanFactory: this interface inherits from BeanFactory and extends the query methods of Bean based on BeanFactory, such as getting BeanNames based on type, BeanNames based on annotations, getting annotations based on Bean, etc.
AutowireCapableBeanFactory: this API inherits from BeanFactory and provides Bean creation, configuration, injection, destruction and other operations on the basis of BeanFactory. Sometimes when we need to manually inject Bean ourselves, we can consider implementing this interface. One of the important applications of AutowireCapableBeanFactory in Spring Security is ObjectPostProcessor, which will be introduced in detail in the Spring Security series.
HierarchicalBeanFactory: this interface inherits from BeanFactory and adds a method to get parent beanfactory based on BeanFactory.
SingletonBeanRegistry: this interface defines the definition of a singleton Bean and how to get it.
ConfigurableBeanFactory: this API mainly defines various configurations and destruction methods for BeanFactory.
ConfigurableListableBeanFactory: this is the configuration list of BeanFactory, where the ignored types and interfaces are defined, BeanDefinition is obtained through the name of Bean, BeanDefinition is frozen, and so on.
AliasRegistry: this interface defines registration, removal, judgment, and query operations for alias.
SimpleAliasRegistry: this class implements the AliasRegistry interface and the methods in it. SimpleAliasRegistry uses ConcurrentHashMap as the carrier to register, remove and query alias.
DefaultSingletonBeanRegistry: this class implements the SingletonBeanRegistry interface based on the collection in Java.
FactoryBeanRegistrySupport: this class inherits from DefaultSingletonBeanRegistry and adds operations such as getting the FactoryBean type, removing the FactoryBean cache, and so on, based on DefaultSingletonBeanRegistry.
AbstractBeanFactory: implements the ConfigurableBeanFactory interface and inherits from FactoryBeanRegistrySupport, and implements the methods defined in ConfigurableBeanFactory in AbstractBeanFactory.
AbstractAutowireCapableBeanFactory: this class inherits from AbstractBeanFactory and implements the methods defined in the AutowireCapableBeanFactory interface.
BeanDefinitionRegistry: this interface inherits from the AliasRegistry interface and adds a series of registration, removal, query, judgment, and other methods for BeanDefinition.
The final DefaultListableBeanFactory naturally has all the above functions.
The above content may dazzle everyone, brother Song here through a few simple practical examples, to take you to use the function of DefaultListableBeanFactory, we may have a clearer understanding.
As an aggregator, DefaultListableBeanFactory provides a lot of functions, let's look at them one by one.
two。 Code modification
First of all, we can slightly modify the first three lines of code in the article, because we have already said that most of the functions in XmlBeanFactory are actually provided in DefaultListableBeanFactory, XmlBeanFactory only makes some customizations to read the IO stream, and the reading of files is mainly done through XmlBeanDefinitionReader (as mentioned in the previous article in this series), we can modify the three lines of code at the beginning of the article. To better reflect that "most of the features in XmlBeanFactory are actually already available in DefaultListableBeanFactory":
ClassPathResource res=new ClassPathResource ("beans.xml"); DefaultListableBeanFactory factory=new DefaultListableBeanFactory (); XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader (factory); reader.loadBeanDefinitions (res); User user = factory.getBean (User.class); System.out.println ("user =" + user)
Use the first four lines of code instead of XmlBeanFactory, so is the function of XmlBeanFactory clear? Is the function of the first four lines of code.
3. Dynamically register Bean
Dynamically register Bean, which is one of the functions of DefaultListableBeanFactory, but it should be dynamic registration of BeanDefinition.
Let's start with a simple example:
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory (); GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition (); MutablePropertyValues pvs = new MutablePropertyValues (); pvs.add ("username", "javaboy"); pvs.add ("address", "www.javaboy.org"); userBeanDefinition.setPropertyValues (pvs); userBeanDefinition.setBeanClass (User.class); defaultListableBeanFactory.registerBeanDefinition ("user", userBeanDefinition); User user = defaultListableBeanFactory.getBean (User.class); System.out.println ("user =" + user)
First, we manually build a DefaultListableBeanFactory object ourselves. Of course, you can also use the previous XmlBeanFactory.
Then build a GenericBeanDefinition manually. In the previous article, Brother Song told you that now the default BeanDefinition is GenericBeanDefinition, so here we also manually build a GenericBeanDefinition. With GenericBeanDefinition, we set the relevant classes and properties.
Next, register userBeanDefinition with defaultListableBeanFactory. Once the registration is complete, we can get the corresponding Bean from defaultListableBeanFactory.
Here is a digression, I hope that when you read each article in this series, you will be able to understand the articles before and after this series, so that there will be a lot of unexpected gains. For example, we can declare either a DefaultListableBeanFactory or a XmlBeanFactory, so you can probably infer that the main purpose of XmlBeanFactory may be to read and register resource files.
So how on earth did you register? Let's look at the definition of the defaultListableBeanFactory.registerBeanDefinition method:
@ Override public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {Assert.hasText (beanName, "Bean name must not be empty"); Assert.notNull (beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) {try {((AbstractBeanDefinition) beanDefinition). Validate ();} catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException (beanDefinition.getResourceDescription (), beanName, "Validation of bean definition failed", ex) }} BeanDefinition existingDefinition = this.beanDefinitionMap.get (beanName); if (existingDefinition! = null) {if (! isAllowBeanDefinitionOverriding ()) {throw new BeanDefinitionOverrideException (beanName, beanDefinition, existingDefinition);} else if (existingDefinition.getRole ()
< beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } } registerBeanDefinition 方法是在 BeanDefinitionRegistry 接口中声明的,DefaultListableBeanFactory 类实现了 BeanDefinitionRegistry 接口,并实现了该方法,我们来看分析下该方法: 首先对传入的 beanDefinition 对象进行校验,这也是注册前的最后一次校验,不过这个时候 BeanDefinition 对象已经到手了,所以这个校验并非 XML 文件校验,这里主要是对 methodOverrides 的校验。 接下来会根据 beanName 从 beanDefinitionMap 中获取 BeanDefinition,看看当前 Bean 是否已经定义过了。beanDefinitionMap 是一个 Map 集合,这个集合中 key 是 beanName,value 是 BeanDefinition 对象。 如果 BeanDefinition 已经存在了,那么接下来会判断是否允许 BeanDefinition 覆盖,如果不允许,就直接抛出异常(不知道小伙伴们有没有印象,在松哥前面的 OAuth3 系列教程中,经常需要配置允许 BeanDefinition 的覆盖,就是因为这个原因,公众号【江南一点雨】后台回复 OAuth3 获取该教程),如果允许 BeanDefinition 的覆盖,那就向 beanDefinitionMap 中再次存一次值,覆盖之前的值。 如果 BeanDefinition 不存在,那就直接注册。直接注册分两种情况:项目已经运行了和项目还没运行。 如果项目已经运行,由于 beanDefinitionMap 是一个全局变量,可能存在并发问题,所以要加锁处理。否则就直接注册,所谓的注册就是把对象存入 beanDefinitionMap 中,同时将 beanName 都存入 beanDefinitionNames 集合中。 这便是 registerBeanDefinition 方法的工作流程。 有小伙伴会说,这个方法从头到尾都是 BeanDefinition,跟 Bean 有什么关系呢? 咋一看确实好像和 Bean 没有直接关系。 其实这涉及到另外一个问题,就是 Bean 的懒加载。这个时候先把 BeanDefinition 定义好,等到真正调用 Bean 的时候,才会去初始化 Bean。我们可以在 User 类的构造方法中打印日志看下,如下: public class User { private String username; private String address; public User() { System.out.println("--------user init--------"); } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", address='" + address + '\'' + '}'; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } 从下图可以看到,当 BeanDefinition 注册完成后,User 并没有初始化,等到 getBean 方法被调用的时候,User 才初始化了。It should be noted that the ApplicationContext we use in our daily development is not lazy loading.
So what if you don't want to load lazily? Of course there's a way.
4. Register for Bean in advance
There is also a preInstantiateSingletons method in DefaultListableBeanFactory that registers Bean in advance, which is declared in the ConfigurableListableBeanFactory interface, and the DefaultListableBeanFactory class implements the ConfigurableListableBeanFactory interface and the methods in the interface:
Override public void preInstantiateSingletons () throws BeansException {if (logger.isTraceEnabled ()) {logger.trace ("Pre-instantiating singletons in" + this);} / / Iterate over a copy to allow for init methods which in turn register new bean definitions. / / While this may not be part of the regular factory bootstrap, it does otherwise work fine. List beanNames = new ArrayList (this.beanDefinitionNames); / / Trigger initialization of all non-lazy singleton beans... For (String beanName: beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition (beanName); if (! bd.isAbstract () & & bd.isSingleton () & &! bd.isLazyInit ()) {if (isFactoryBean (beanName)) {Object bean = getBean (FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) {final FactoryBean factory = (FactoryBean) bean; boolean isEagerInit If (System.getSecurityManager ()! = null & & factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged ((PrivilegedAction) ((SmartFactoryBean) factory):: isEagerInit, getAccessControlContext ());} else {isEagerInit = (factory instanceof SmartFactoryBean & & (SmartFactoryBean) factory). IsEagerInit ();} if (isEagerInit) {getBean (beanName) } else {getBean (beanName);} / / Trigger post-initialization callback for all applicable beans... For (String beanName: beanNames) {Object singletonInstance = getSingleton (beanName); if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager ()! = null) {AccessController.doPrivileged ((PrivilegedAction) ()-> {smartSingleton.afterSingletonsInstantiated (); return null;}, getAccessControlContext ());} else {smartSingleton.afterSingletonsInstantiated ();}
The overall logic of the preInstantiateSingletons method is relatively simple, which is to traverse the beanNames and instantiate the qualified Bean, and note that the so-called pre-initialization here is actually calling getBean before we call the getBean method.
We can call this method manually in the case:
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory (); GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition (); MutablePropertyValues pvs = new MutablePropertyValues (); pvs.add ("username", "javaboy"); pvs.add ("address", "www.javaboy.org"); userBeanDefinition.setPropertyValues (pvs); userBeanDefinition.setBeanClass (User.class); defaultListableBeanFactory.registerBeanDefinition ("user", userBeanDefinition); defaultListableBeanFactory.preInstantiateSingletons (); User user = defaultListableBeanFactory.getBean (User.class); System.out.println ("user =" + user)
At this point, User is initialized before the getBean method is called, as shown below:
5.getBean
Another heavyweight method in DefaultListableBeanFactory is getBean. However, the real implementation of the getBean method is in the parent class AbstractBeanFactory of DefaultListableBeanFactory, and the specific implementation method is doGetBean. I originally wanted to talk about this problem with my family here, but I found that this is a very huge problem, and neither BeanFactory nor FactoryBean have shared it with you yet, so let's postpone this topic for a while and click on it one by one.
At this point, the study on "how to understand container DefaultListableBeanFactory" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.