Written in the beginning
This chapter introduces the complete technology of the Spring framework. The purpose of this article is to write, on the one hand, in order to give the beginning of the backend development of a talent guide, on the other hand is for their own access to basic knowledge.
Spring is not necessarily the best framework (although it has the most comprehensive capabilities), but it is certainly the best ecology. Community, official documentation, updates, iterations, etc., have been very effective. Although THERE are not many frameworks I have contact with, there are only Spring and Netty frameworks that can bring me amazing and smooth when I learn them. So, before I take the graduate school entrance exam and completely abandon the development, I plan to write an article to explain exactly what Spring is.
I prefer Java Configuration(which is also recommended by “Spring Practice” (my Spring introduction book, quite good)), so please note that in the case of the same Configuration, I will omit the XML Configuration table.
Spring Framework Core 5.2.5 RELEASE
Because considering postgraduate entrance examination, project development, etc., so the article update will be slow (in fact, the main translation summary is a physical work, I am also a little lazy…) If you like, you can also send me a private message to remind me of the update!
QQ: 2508826394 ag d2508826394 E-mail: 2508826394 @qq.com/[email protected] nuggets: direct messages I see directlyCopy the code
My ability is limited, if you think there is any problem with the description, please be sure to contact me, to avoid misleading others, thank you very much! If I am unsure about the translation part, I will directly attach to the original text.
Required basic knowledge (operation) :
Java SE(Version 11.0+)
Maven(Version 3.62+)
JetBrains IntelliJ IDEA(Version 2019.3.4+)
GitHub
Copy the code
The full text is about 20,000 words, please know!
The understanding of obscure words that appear
Configuration metadata: The meaning of a configuration source or configuration file.
Dependencies: As the name implies, the other instances needed to build an instance, which are called “dependencies” because they depend on this instance.
Bean: A class instance that is generated and destroyed by the framework.
DAO: Data Access Object (DAO), is a class of beans used to Access the database
The higher the coupling between A and B, the stronger the interdependence between them. Software design pays attention to low coupling, for the convenience of later maintenance, so as not to “touch the whole”.
Property: Property, which is actually a private domain.
POJO: Chinese translation, simple Java objects. It’s a class, similar to a Bean, that acts as a data carrier with only setter and getter methods, sometimes overriding hashCode(), equals(), toString(), etc.
AoolicationContext: Application context, what does that mean? Have you done reading comprehension? You can get beans, configuration files, system resources, startup information, and so on from ApplicationContext. So “context” means that the manager of the program, who owns the entire program, can penetrate everywhere to manage operations. (I really understood for a long time!)
Callback method: this method is automatically called when an operation completes, as described in listener design pattern.
Post: The Chinese translation is both in… The meaning of the following, and the meaning of the application, in the following class name understanding may be useful, so specially picked out.
Aware: The Aware interface, which is intrusive, gives the implementing Bean the ability to obtain the Bean’s basic information (e.g. name, class) from the container, similar to granting the Bean VIP membership privileges.
The introduction
The most important thing in the Spring Framework is the Inversion Of Control(IOC) Of the Spring Framework. This article begins with an introduction to IOC techniques, followed by the complete and comprehensive Spring Framework aspect-Oriented Programming(AOP). Conceptually, Spring’s AOP is well understood, and it can also solve 80% of AOP problems in enterprise programming.
Spring incorporates AspectJ, one of the richest and most mature implementations of Java enterprise-wide AOP currently available. (Suggesting that Spring AOP is awesome)
The IOC container
Introduction to the Spring IOC container and beans
IOC is also known as Dependency Injection(DI). It is the process of defining dependencies for an object that obtains the dependencies (other objects) needed to create it from the construction parameters, factory method parameters, and property values.
Containers are a bit of a show! This process essentially “takes over” the object’s control of the dependency by directly constructing a class or a mechanism similar to the service location pattern instead of implementing the bean’s instantiation or location process. That’s why it’s called Inversion of Control.
Org. Springframework. Beans and org. Springframework. The context of these two bags is the basis of the Spring Framework IOC container bags, including: The BeanFactory interface provides an advanced configuration mechanism that can manage any type of object. ApplicationContext is a subinterface that has:
A) Integrate Spring AOP features more easily. B) Manage resource processing. C) Publish events. D) Application-level special context, such as WebApplicationContext in Web applications.Copy the code
In short, BeanFactory provides the configuration framework and basic functionality, and ApplicationContext adds some functionality for enterprise development. Application is a complete superset of BeanFactory and is used only to describe the Spring IOC container in this chapter. To learn more about BeanFactory, see here
In Spring, the object instances that form the backbone of your application are called “beans.” What are beans? Is an instantiated, assembled, and managed object by the Spring IOC container. Beans are just one of many objects in your application. All beans, and the dependencies they use, are managed by the container using reflection using configuration metadata.
Container overview
Org. Springframework. ApplicationContext interface represents the Spring IOC container, it is responsible for instantiating, configuration and assembly of bean. The container reads the configuration metadata to determine which objects to instantiate, configure, and assemble. Metadata is in the form of XML, Java annotations or Java code. It allows you to clearly specify the objects that make up your application and the rich internal dependencies between them.
The following figure shows how Spring works:
Configuring metadata
As shown in the figure, the Spring IOC container uses a form composed of configuration metadata. This form contains configuration metadata that represents how you, the application developer, want the Spring container to instantiate, configure, and assemble the Bean components in your application.
The traditional method of setting configuration metadata is to use XML, which is the main configuration method in this chapter.
P.s. XML is not the only format, the Spring IOC container is decoupled from it, and more and more developers are using Java annotation-based configuration methods (like me) these days.Copy the code
Want to learn more about other configuration formats?
* Annotation-based configuration (introduced in Spring 2.5)
Java-based configuration (Introduced with Spring 3.0, some of the features provided by Spring JavaConfig have gradually become the core of the Spring Framework, so you can use Java configuration to provide external beans for your application instead of using XML files. Want to use these new features? Try @Configuration, @Bean, @import, @dependson)
The Spring Configuration takes into account that the container manages at least one (and usually many)Bean definitions, and the Java Configuration uses the @Bean annotation to define these beans in the @Configuration annotated classes.
These Bean definitions are associated with instance objects and then decorate your application. Typically, you will define business layer objects such as daos (database Access Objects), representation objects such as Struts Action instances, infrastructure objects such as Hibernate SessionFactories, JMS queues, And so on. Typically, loading domain objects is the responsibility of the DAO or business logic, so there are no fine-grained domain objects in the container. However, you can use Spring’s integration with AspectJ to configure objects created outside the control of the IOC container. See.
Simple usage:
public class Book
{
// ...
}
@Configuration
public class WebConfig
{
// ...
@Bean(name = "book")
public Book book(a)
{
return newBook(); }}Copy the code
The XML configuration:
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<! -- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<! -- collaborators and configuration for this bean go here -->
</bean>
<! -- more bean definitions go here -->
</beans>
Copy the code
To reference a configuration class to another configuration class, precede the class with:
@Import(value = {ConfigA.class, ConfigB.class})
Copy the code
Or XML form:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
Copy the code
Using a container
By use:
T getBean(String name, Class<T> requiredType)
Copy the code
Method to get the Bean instance.
Ideally, however, you shouldn’t use the getBean() method because it breaks the container’s automatic management of objects. You can use annotations such as @autowired to get the dependencies you need in a particular Bean. To be clear, call getBean() except for tests. Otherwise, you have an IOC container to manage it for you. Direct oneself whole bai! Brother!)
An overview of the Bean
Within the IOC container, the definition of a Bean is presented as a BeanDefinition. They contain the following metadata:
A) a class with a package-qualified name that contains the implementation class of the Bean. B)Bean behavior definition component, which defines the behavior of beans in the IOC container. C) References to other beans that this Bean needs, which are also called "collaborators" or "dependencies." D) Other configurations used to set the newly created Bean, such as the timeout period, the number of database connection pools, etc.Copy the code
The metadata is passed into a configuration collection to express the Bean definition.
See the detailed Bean configuration collection.
ApplicationContext also allows users to customize beans outside of the container. Through ApplicationContext getBeanFactory () method, the method returns the BeanFactory DefaultListableBeanFactory implementation, DefaultListableBeanFactory support through registerSingleton (..) And registerBeanDefinition (..) To register the Bean. Typically, however, an application can only work with beans defined through configuration metadata.
Named Bean
A Bean usually contains one or more unique identifiers. If the bean name is not indicated, the default name (lowercase class name) is used, and the bean name follows the Java naming convention of lowercase first + hump. You can also use aliases (which, seriously, are usually not).
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Copy the code
Instantiate the Bean
With XML, you should indicate (compulsively) its type. In this way, you can create an instance by calling the constructor of the class, equivalent to new; You can also call static factory methods to create. When you create with a constructor, the container will find its own constructor, so you just need to write it like a normal class. It’s better to have a constructor with no parameters.
For example:
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
Copy the code
Not only can the Spring container manage entity classes, but virtual classes can also be managed by it, for example, database connection pools that do not conform to the Java Bean specification.
For XML configuration, when using static factory methods, class refers to the factory class and factory-method refers to the specific static method. If you use instance factory methods, just change the class attribute to a factory-bean and point to the factory class.
Such as:
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
Copy the code
Example factory method:
<! -- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<! -- inject any dependencies required by this locator bean -->
</bean>
<! -- the bean to be created via the factory bean -->
<bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
Copy the code
Rely on
Typical enterprise-level applications do not contain singletons, and even the smallest applications require one object to be embedded by another in order to run. This section describes how to define Bean configurations to organize individual objects for a fully decoupled application.
Dependency injection
Dependency Injection (DI) refers to a process in which an object can define its Dependency only through constructor parameters, factory method parameters, property values after the object instance is constructed, or the factory method return value. The container actively injects these dependencies when creating these beans, a process known as the Bean’s own control over dependency acquisition, reversing this responsibility.
Thanks to DI, the code is cleaner and decoupled more efficiently. Beans don’t actively introduce the dependencies they need, so testing is easier. Since some beans are implementation classes for interfaces, it’s easy to erase some features and add new ones to test!
- Constructor based DI
Constructor-based DI is accomplished by the container calling constructors with or without arguments. The same effect can be achieved by calling static factory methods. Here is an example of constructor injection:
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Copy the code
XML format
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
Copy the code
Type matching:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
Copy the code
Sequence matching:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
Copy the code
Name match:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
Copy the code
- Analytical construction parameter
In other words, when there is ambiguity about the matching order of constructor parameters, the order should be explicitly specified. In Java Configuration, @autowired is done, the whole is so much to remember!
- Setter based DI
After the container calls your parameterless constructor or parameterless static factory method, it calls your setter method for dependency injection. Here’s an example:
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Copy the code
In addition to the above two types of injection, ApplicationContext also supports injection by calling setters again after constructor injection.
Constructor injection and setter injection compare:
Using the @Required annotation on the setter method makes this property a dependency that must be injected. Controller injection with parameter validation is a better choice.
The Spring team recommends using constructor injection, which reduces the risk of component built-time parameter changes and non-null determinations to a greater level. In the long run, the beans built by this method are usually the perfect beans to initialize their state. Too many construction parameters, probably your code is too garbage, refactor! The young!
Setter method injection is usually used for optional dependencies, which can usually be specified with a default value, but beware of non-null checks. The benefit of setter injection is that dependencies can be reconfigured or injected later, increasing flexibility.
With dependency injection, third-party objects can enjoy the convenience of container management, but once the third-party class does not have setter methods, the dependency can only be injected through the constructor.
- Dependency resolution process
The dependency resolution process for the container is as follows:
A) Create and initialize the ApplicationContext by configuring metadata (e.g. XML files, Java code, annotations). B) For each Bean, its dependencies are presented as properties, constructor parameters, and static factory method parameters that are automatically added when the Bean is created. C) Each attribute or constructor parameter is a reference to another Bean in the container, or the actual definition of a value to be set. D) The value of each property or constructor parameter is the value converted from a special type to the actual type of the property or constructor parameter. By default, Spring converts a String value to eight basic types.Copy the code
Spring validates the validity of each Bean configuration when the container is created, and the Bean properties are not set until the Bean is created. Singletons and pre-created beans are created at the same time as the container is created. The rest of the beans are created when they need to be created, because each creation causes a chain reaction (Bean dependencies are created, Bean dependencies are created…). , so a resolution for a mismatch may come later.
Be careful to avoid circular dependencies, where A depends on B, B depends on C, and C depends on A. In this case, it is important to avoid, for example, using setter-based DI to reduce dependencies.
The Spring container anticipates potential problems (such as null Pointers, circular references) during loading. Spring sets the properties as late as possible, which indicates that you might initially create a Bean normally, but later throw an exception. This is why ApplicationContext uses pre-created as the default. Trading time and memory for a more reliable system (finding more potential problems) when the ApplicationContext is created, rather than finding problems when they need to be created, is the approach Spring takes. Of course, you can override this strategy and implement singletons (as late as possible).
If nothing happens, Spring will start injecting beans, and Spring will pre-configure the dependencies required for the beans to be created. This means that if A needs B, Spring might initialize A, then configure B, and then call A’s setter methods to complete DI. In other words, a Bean is created, its setter methods are called to inject dependencies, and the associated lifecycle methods are called.
- Example of dependency injection
<bean id="exampleBean" class="examples.ExampleBean">
<! -- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<! -- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
Copy the code
Dependencies and details configuration
As mentioned earlier, you can set attributes or constructor parameters by referring to other container-managed beans that have built-in values.
- Direct value
A string written inside a property tag (<property/>) can be injected as an attribute value. This is an XML file, and is typically used in the MyBatis database configuration.
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<! -- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="masterkaoli"/>
</bean>
Copy the code
P – the namespace instance:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="masterkaoli"/>
</beans>
Copy the code
Java. Util. Properties instances:
<bean id="mappings"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<! -- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
Copy the code
Idref tag:
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean"/>
</property>
</bean>
Copy the code
Equivalent to this (runtime)
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean"/>
</bean>
Copy the code
- Reference other beans
Set the properties of the current Bean by referring to other beans managed by this container.
Example:
<bean id="accountService" <! -- bean name is the same as the parent bean --> class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref parent="accountService"/> <! -- notice how we refer to the parent bean --> </property> <! -- insert other configuration and dependencies as required here --> </bean>Copy the code
- Inside the Bean
An anonymous Bean is created to create this Bean, just as an anonymous class is created inside the class. Cannot be managed, accessed, or injected by the container. It is just a helper Bean that generates this Bean.
Example:
<bean id="outer" class="...">
<! -- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <! -- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
Copy the code
- A collection of
The collection label can be used to set the collection type of the Bean. Common collections can be used.
Here’s an example:
<bean id="moreComplexObject" class="example.ComplexObject">
<! -- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">[email protected]</prop>
<prop key="support">[email protected]</prop>
<prop key="development">[email protected]</prop>
</props>
</property>
<! -- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<! -- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<! -- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
Copy the code
For set merging
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">[email protected]</prop>
<prop key="support">[email protected]</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<! -- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">[email protected]</prop>
<prop key="support">[email protected]</prop>
</props>
</property>
</bean>
<beans>
Copy the code
- The String values of Null and Empty
An empty string is a property with a value of “”, or Null if the property is not set.
- Compound attribute name
It’s literally, it’s the property of the property, it’s the property of the property, it’s the property of the property.
Such as:
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
Copy the code
Use the depends – on
You can force the dependencies used by this Bean to be forcibly initialized when initializing the Bean.
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
// or
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
Copy the code
Delayed initialization of the Bean
Is a property that indicates whether the initialization is delayed.
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
Copy the code
Container-level latency:
<beans default-lazy-init="true">
<! -- no beans will be pre-instantiated... -->
</beans>
Copy the code
Automatic weaving into the collaborator
You can set auto weaving mode by setting the Autowire property of <bean/>. Advantages of automatic weaving:
A) Greatly reduces the need to specify attributes or constructor parameters. B) When your application is updated, the configuration can be updated automatically. This feature is very useful for development purposes.Copy the code
Automatic weaving has four modes
A)no: Automatic weaving is disabled and dependencies are referenced by referencing other beans. B)byName: automatically woven based on the attribute name c)byType: woven if the container has this attribute type. D)constructor: similar to byType, but only for constructor arguments.Copy the code
Limitations and limitations of automatic weaving:
I'll leave it at that.Copy the code
Remove autowoven beans
I'll leave it at that.Copy the code
Methods to inject
Background: Most of the time, most beans are singletons, and when a singleton Bean needs to work with another singleton Bean, or a non-singleton Bean needs to work with another non-singleton Bean, you usually deal with dependencies by defining one Bean as a property of the other. When the Bean lifecycle is inconsistent, ho, ho, the problem comes. Assume that the singleton Bean A is going to use the non-singleton Bean B on every method call to A. The container will only create an instance of A once, so there is only one chance to set property B, but the container cannot provide A new instance every time it needs B. This creates problems.
One solution is to temporarily cancel some IOC by implementing the ApplicationContextAware interface to let A discover the container and get A new instance of B each time it is needed by calling the container’s getBean(“B”) method. Here’s an example:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand(a) {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext( ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext; }}Copy the code
The above code is coupled to the Spring framework, so it’s not recommended, but it does allow you to write clean processing code.
- Find method injection
Lookup method injection is the ability of the container to override a method of the current Bean using a method of another Bean managed by the container. The lookup usually calls the prototype Bean, and Spring implements this method injection by dynamically subclassing it through CGLIB’s dynamic proxy.
In other words, Spring uses a dynamic proxy to override or subclass a method of an abstract class that is not implemented. @lookup tells Spring which method of the same name to implement.
Suppose there are the following classes that need proxies:
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand(a);
}
Copy the code
The proxied method should have the following method signature:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
Copy the code
For the XML form, there are the following methods:
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
<! -- inject dependencies here as required -->
</bean>
<! -- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="myCommand"/>
</bean>
Copy the code
For the annotation form, you can declare the lookup method as follows:
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand(a);
}
Copy the code
Or, a more concise way to find the Bean is by returning its value:
public abstract class CommandManager {
public Object process(Object commandState) {
MyCommand command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract MyCommand createCommand(a);
}
Copy the code
- Arbitrary method substitution
A slightly less useful use of the lookup method is to replace any method of the beans in the container with another method implementation. You can skip it and come back to it later. Consider the following classes:
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
// some other methods...
}
Copy the code
Then there is a class that provides a new implementation of this method, as follows:
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
// get the input value, work with it, and return a computed result
String input = (String) args[0]; .return. ; }}Copy the code
Perhaps by the class name to determine the unique replacement…
Class name format: Replacement+ Name of the method to be replaced + Implement MethodReplacer.
XML looks like this:
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
<! -- arbitrary method replacement -->
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
Copy the code
The Bean scope
When you create a Bean definition, you also create a rule based on the Bean definition. This rule specifies how to create instances of the class, whether singletons or prototype beans. This is an important idea in that you can create multiple object instances of a class based on the same creation rule.
Not only can you control the various dependency and configuration values injected into objects created from a Bean definition; You can also control the scope of objects created from an exact Bean definition. This approach is powerful and flexible because you can scope objects by configuration rather than re-scoping them at the Java class level. Beans can be used in one of these scopes. The Spring Framework has six scopes, the last four of which are available only when you write web-aware ApplicationContext. Of course, you can also customize the scope.
Look at a description table:
scope | describe |
---|---|
Singleton (singleton) | The same Bean instance is shared for all references to the same Bean in each IOC container. |
The prototype (prototype) | For each reference, a new instance is created. |
Request (request) | Each HTTP request has its own instance object reference. |
Session (session) | Limit the scope to one HTTP Session lifetime. |
Application (application) | Limit the scope to the Lifetime of the ServletContext |
WebSocket(websocket) | Limit the scope to the WebSocket declaration cycle. |
Thread (thread) | Spring 3.0+ only,see.As shown in the |
Singleton Bean
Ahem, what is a singleton Bean? When only one shared Bean instance is managed by the container, this is called a “singleton Bean”. All references, requests, to this Bean get the same instance.
When you define a singleton Bean, the Spring IOC container will simply create an instance of the Bean based on the Bean definition, cache it in the singleton Bean cache pool (which is full of singleton beans), and all requests for that Bean will get a reference to that singleton Bean.
. Why does the official text say so pissant? (the fog? . In plain English, all Bean object references share one instance; Unlike new, each object can have its own instance; Global variables, okay? Everyone uses it! That’s the singleton Bean.
Let’s have a tukangkang
For annotation-based configuration, use the following:
@Scpoe(ConfigurableListableBeanFactory.XXX)
@Component
public class ClassA
{
// ...
}
Copy the code
XML usage:
<bean id="accountService" class="com.something.DefaultAccountService"/>
<! -- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
Copy the code
Prototype Bean
Stereotype beans are different from singletons in that the container creates an instance object for each request. You should know that stereotype beans should be used for stateful beans and singletons are recommended for stateless beans.
Take a picture of Kangkang:
Here’s an example of a prototype Bean setup:
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
Copy the code
Unlike singleton beans, prototype beans are created only by the container, and the container is not responsible for their full lifecycle. Therefore, resource release of prototype beans is handled manually. Or by using a custom bean post-processor.
In a way, the Spring container is to prototype beans what Java’s New is; all lifecycle methods except creation should be handled by the writer.
A singleton Bean with prototype Bean dependencies
If a singleton Bean needs a prototype Bean as a dependency, remember that each injection of a dependency is a new instance, and that different properties cannot share the same dependency instance. If you want to share a dependency, consider method injection.
Request, Session, Application, and WebSocket scopes
Some initialization steps are usually required before use, but are not required. If you are using Spring MVC, DispatcherServlet will do the prep work for you, and some older Servlet containers may require you to configure some start-up requirements yourself.
- Request the domain
How to create a request domain Bean
<bean id="loginAction" class="com.something.LoginAction" scope="request"/>
Copy the code
Or the Java configuration
@RequestScope
@Component
public class LoginAction {
// ...
}
Copy the code
The life cycle of the Request Bean is only the current Request. The end of the Request is created and the completion of the Request is destroyed.
- Session domain
Create:
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
Copy the code
The Java configuration
@SessionScope
@Component
public class UserPreferences {
// ...
}
Copy the code
The lifecycle is the same as that of an HTTP Session. When the Session is created, this class Bean is created, and when the Session is destroyed, this class Bean is destroyed.
- Application domain
Create:
<bean id="appPreferences" class="com.something.AppPreferences" scope="application"/>
Copy the code
The Java configuration:
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
Copy the code
Similar to a singleton Bean, because the entire Web application shares the same instance, the Bean is set as a property of the ServletContext and so exists consistently throughout the Web. The difference with a singleton Bean is that it belongs to a ServletContext rather than ApplicationContext. The second is that it is used as a ServletContext property.
- Use the qualified Bean as a dependency.
For use of HTTP-Request-scoped beans as dependency injection into a long-life Bean, a proxy may be needed. One way to do this is to use an AOP proxy.
I don’t use this much, so I’ll skip it, and I’ll put the link here
- Select the type of agent you want to create
Ditto. I’ll skip it.
Custom scope
- Create a custom scope
Thinking of your own scope to integrate into the Spring container inside, you need to implement org. Springframework. Beans. Factory. Config. The scope interface. Check out the Java Doc to learn more.
The Scpoe interface has four methods to obtain, remove, and destroy objects.
Object get(String name, ObjectFactory
objectFactory)
Object remove(String name)
void registerDestructionCallback(String name, Runnable destructionCallback)
String getConversationId(a)
Copy the code
- Use a custom scope
You need to register the Scope in the Spring container using the registerScope method of the ConfigurableBeanFactory. A ConfigurableBeanFactory can be obtained from the BeanFactory property of the ApplicationContext.
Example:
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
Copy the code
Custom Bean properties
Spring provides a series of interfaces for implementing custom Bean properties.
Life cycle callback
To make your own Bean interact with the container, you’ll implement the InitializingBean interface and DisposableBean interface. The container will call afterPropertiesSet() in the previous phase, destroy() in the later phase, and Causes your Bean to behave when it is initialized and destroyed.
Inside Spring, the Spring framework uses the BeanPostProcessor implementation class to handle the callback interfaces it can find and call the appropriate methods. If you want to customize a behavior that Spring does not provide by default, implement the BeanPostProcessor, which is detailed here
In order to initialize and destroy the callback, Spring-managed objects may also need to implement the Lifecycle interface, so that they can actually “open” and “close” operations as driven by the container’s own Lifecycle (by implication, in line with the container’s Lifecycle).
- Initialize the callback
Org. Springframework. Beans. Factory. InitializingBean interface beans in the container to add after all rely on has the capacity to initialize behavior. The method declaration is as follows:
void afterPropertiesSet(a) throws Exception;
Copy the code
However, we don’t recommend using this interface because it will couple your code to Spring. We recommend using the @PostConstruct annotation, or specifying an initialization method for the POJO. Example of specifying an initialization method:
The XML configuration
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
Copy the code
The Java configuration
public class BeanOne {
public void init(a) {
// initialization logic}}public class BeanTwo {
public void cleanup(a) {
// destruction logic}}@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne(a) {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo(a) {
return newBeanTwo(); }}Copy the code
Note that the initialization method should be a no-parameter method.
The above method is equivalent to the following:
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet(a) {
// do some initialization work}}Copy the code
- Destruction of the callback
Org. Springframework. Beans. Factory. DisposableBean interfaces provided in the measures can be taken when the Bean is destroyed, the method statement is as follows:
void destroy(a) throws Exception;
Copy the code
Again, Spring does not recommend using this interface, instead using the @preDestroy annotation or specifying the destroy method. Here’s an example:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
Copy the code
The Java configuration
public class BeanOne {
public void init(a) {
// initialization logic}}public class BeanTwo {
public void cleanup(a) {
// destruction logic}}@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne(a) {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo(a) {
return newBeanTwo(); }}Copy the code
The destruction method should also take no arguments.
The above method is equivalent to the following:
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy(a) {
// do some destruction work (like releasing pooled connections)}}Copy the code
- Default initialization and destruction methods
In addition to specifying initialization and destruction methods, Spring also offers to proactively call initialization or destruction methods by looking them up by name, which is the default. The default is to look for and call by name, but the default methods, such as the initialization method “init()” and the destruction method “destroy()”, must be called by the Spring container as default methods.
Such as:
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init(a) {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set."); }}}Copy the code
For XML format
<beans default-init-method="init">
<bean id="blogService" class="com.something.DefaultBlogService">
<property name="blogDao" ref="blogDao" />
</bean>
</beans>
Copy the code
The default method should be declared in the top-level <beans/> tag. Of course, you can override the default method by specifying the initialization or destruction method in the <bean/> tag.
- Composite lifecycle mechanisms
Spring provides a variety of mechanisms, and it’s time to summarize them.
Actions that can generate initialization behavior:
A) Methods annotated with @PostConstruct b) afterPropertiesSet() methods of the InitializingBean interface c) custom init() methodsCopy the code
Actions that can generate destruction behavior:
A) @preDestroy annotation method b)DisposableBean interface's destroy() method c) custom Destroy () methodCopy the code
- Turning on and off (lifecycle) callbacks
The Lifecycle interface defines several potential methods for any object that has its own Lifecycle requirements. Look at the interface:
public interface Lifecycle {
void start(a);
void stop(a);
boolean isRunning(a);
}
Copy the code
Any Spring-managed object is likely to implement this interface, and when ApplicationContext itself is started or destroyed, it hierarchically triggers the start and stop methods of the beans it manages. Of course, it does this by proxying this process to the LifecycleProcessor interface. See the definition:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh(a);
void onClose(a);
}
Copy the code
In addition to the three methods inherited from Lifecycle, this interface adds two methods of its own to do the same for the beans it manages when ApplicationContext is refreshed and closed.
Note: Lifecycle, is a common agreement applies only to explicitly start and stop, but it doesn’t fit since the start of the refresh phase, if you want to achieve from the start, consider org. Springframework. Context. SmartLifecycle interface. Of course, you should also know that the stop signal is not guaranteed to be notified on the destruction method call. In the normal stop phase, the stop signal is passed to the Bean before the destroy method, but in the hot refresh or abort refresh attempt phase, only the destroy method is called.
The sequence of shutdown and startup is particularly important (nonsense), a Bean should be started after its dependencies are started, and should be closed before its dependencies. But most of the time, only can order according to the type of judgment, it is not enough, we need more, the methods for preparation of fine grained org. Springframework. Context. SmartLifecycle interface inherits from the Phased interface provides such a choice. Look at the code:
public interface Phased {
int getPhase(a);
}
Copy the code
Let’s look at SmartLifecycle:
public interface SmartLifecycle extends Lifecycle.Phased {
boolean isAutoStartup(a);
void stop(Runnable callback);
}
Copy the code
When the container starts, the object with the smallest value starts earliest, but closes last. This means that if phase is set to integer.min_value, this object will start first; When phase is set to integer.max_value, the object starts last and closes first.
The stop method defined by the SmartLifecycle interface receives a callback and any class that implements this interface must call the run() method of the callback method after the closing process has finished. It can ensure asynchronously closed when necessary, because the default implementation class DefaultLifecycleProcessor LifecycleProcessor at each stage wait for timeout time come to call the callback. The default time limit is 30s, of course, you can change this time by yourself. You can override the lifecycleProcessor by implementing a Bean named “lifecycleProcessor”, which, of course, allows you to set the timeout.
For the LifecycleProcessor interface, it also defines the refresh and close operations for the ApplicationContext. The latter only closes when stop() is explicitly called; But it also happens when the ApplicationContext is closed. When ApplicationContext is refreshed, the default Lifecycle processor checks the isAutoStartup() return value of each SmartLifecycle object to determine whether to restart it. The dependencies defined by the phase attribute and the dependence-on attribute determine the start order according to the rules described earlier.
- Gracefully close the Spring IOC container in a non-Web application
If you are using a non-Web application, remember to bind a close operation to the JVM to free the resources held by the singleton Bean. You can “gracefully” close an application by registering the close operation with the JVM as follows:
Call ConfigurableApplicationContext registerShutdownHook () method.
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...
// main method exits, hook is called prior to the app shutting down...}}Copy the code
ApplicationContextAware and BeanNameAware
When the ApplicationContext created an implementation of a org. Springframework. Context. ApplicationContextAware interface instance objects, The instance object gets a reference to ApplicationContext, which is defined as follows:
public interface ApplicationContextAware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
Copy the code
Thus, beans can programmatically manage ApplicationContext manually, and you can get more usage by casting the ApplicationContext interface into a subclass of this interface. A typical use is to fetch other beans. Sometimes this feature is useful, but you should avoid it because it breaks IOC’s nature. Other methods of ApplicationCOntext provide the ability to access file resources, publish application events, and access message resources. For more details, see here.
Automatic weaving is another way to get an ApplicationContext. The traditional method is to inject the ApplicationContext into a constructor or setter method using a type-based method. A more flexible approach is to use the automatic weaving feature to weave in domain or method parameters. This is the way the @Autowired annotation is woven, and it’s the way I like it.
When a Bean implementation org. Springframework. Beans. Factory. BeanNameAware interface, is provides a can modify its Bean Bean the definition name, the method of the following description:
public interface BeanNameAware {
void setBeanName(String name) throws BeansException;
}
Copy the code
Other Aware interfaces
In addition to ApplicationContextAware and BeanNameAware, Spring provides a set of Aware interfaces for beans to use to indicate to the container some of the underlying dependencies they need.
See table:
(The original is not easy to translate, in order to prevent ambiguity, directly put the original)
Name | Injected Dependency | Explained in… |
---|---|---|
ApplicationContextAware | Declaring ApplicationContext. | ApplicationContextAware and BeanNameAware |
ApplicationEventPublisherAware | Event publisher of the enclosing ApplicationContext. | Additional Capabilities of the ApplicationContext |
BeanClassLoaderAware | Class loader used to load the bean classes. | Instantiating Beans |
BeanFactoryAware | Declaring BeanFactory. | ApplicationContextAware and BeanNameAware |
BeanNameAware | Name of the declaring bean. | ApplicationContextAware and BeanNameAware |
BootstrapContextAware | Resource adapter BootstrapContext the container runs in. Typically available only in JCA-aware ApplicationContext instances. | JCA CCI |
LoadTimeWeaverAware | Defined weaver for processing class definition at load time. | Load-time Weaving with AspectJ in the Spring Framework |
MessageSourceAware | Configured strategy for resolving messages (with support for parametrization and internationalization). | Additional Capabilities of the ApplicationContext |
NotificationPublisherAware | Spring JMX notification publisher. | Notifications |
ResourceLoaderAware | Configured loader for low-level access to resources. | Resources |
ServletConfigAware | Current ServletConfig the container runs in. Valid only in a web-aware Spring ApplicationContext. | Spring MVC |
ServletContextAware | Current ServletContext the container runs in. Valid only in a web-aware Spring ApplicationContext. | Spring MVC |
Inheritance principles for Bean definitions
A Bean definition can contain a lot of configuration information, including constructor parameters, property values, and container-specific information such as initialization methods, static factory method names, and so on. A child Bean definition (not a child Bean definition, but a child Bean definition; The configuration metadata from the parent Bean definition is inherited. Subdefinitions can override some attribute values or add new definitions as needed. Using parent-child Bean definitions saves a lot of duplication. In fact, this is a form of a template.
If you use ApplicationContext programmatically, the ChildBeanDefinition is rendered by ChildBeanDefinition. If it’s in XML, look here:
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<! -- the age property value of 1 will be inherited from parent -->
</bean>
Copy the code
If no child definition is specified, the child Bean definition uses the parent Bean definition, but it can still be overridden, in which case the child Bean class must be compatible with the parent Bean class.
The subbean definition inherits scope, constructor parameter values, property values, and method substitutions, as well as the ability to add new values. Any domain, initialization method, destruction method, or static factory method setting you specify will override the corresponding setting in the parent definition.
The following example explicitly declares the parent class abstract, and if the child definition does not explicitly override this setting, then the Bean generated by the child definition will also be abstract
<bean id="inheritedTestBeanWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBeanWithoutClass" init-method="initialize">
<property name="name" value="override"/>
<! -- age will inherit the value of 1 from the parent bean definition-->
</bean>
Copy the code
In general, a class is declared abstract in order to serve as a template to be overridden by its children, and any kind of reference to the Bean defined by the abstract parent will result in an error.
A parent Bean definition is an abstraction that serves as a template to define the child Bean definition. The parent Bean definition itself cannot be instantiated. Only the Bean defined by its child Bean definition can be instantiated.
Note: Any definitions that you want to use only as templates must be declared abstract, otherwise the IOC container will instantiate them in advance.
Extended knowledge of containers
In general, developers do not need to write special subclasses of the ApplicationContext implementation class. Instead, they can inject several special implementation classes of the composite interface.
Customize beans through BeanPostProcessor
BeanPostProcessor provides callback methods. To implement them, you can provide your own initialization logic. If you want to implement some custom logic after the IOC container has instantiated, configured, or initialized the Bean, you can inject one or more BeanPostProcessor implementation classes.
Take a look at the definition of BeanPostProcessor:
public interface BeanPostProcessor {
// Apply this BeanPostProcessor to the given new bean instance before any bean initialization callbacks (like InitializingBean's afterPropertiesSet or a custom init-method).
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// Apply this BeanPostProcessor to the given new bean instance after any bean initialization callbacks (like InitializingBean's afterPropertiesSet or a custom init-method).
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
returnbean; }}Copy the code
You can also define multiple BeanPostProcessors and control the order in which they are executed by setting the order order. The Order attribute can be set only after the BeanPostProcessor implements the Ordered interface. So, if you implement your own BeanPostProcessor interface, implement the Ordered interface in passing. See JavaDoc for details.
Note: a) The BeanPostProcessor instance is used to manipulate the Bean instance, which means that the Spring IOC container is responsible for Bean creation, and the rest of the work is done by the BeanPostProcessor. B)BeanPostProcessor can only be scoped in one container or in its children. Even different children that inherit from the same container cannot share BeanPostProcessor. C) Change the actual Bean definition by using BeanFactoryPostProcessor.Copy the code
Org. Springframework. Beans. Factory. Config. BeanPostProcessor actually contains two callback methods, only when such a class is registered in the container, the container of each Bean, After the post – processor (CPU) initialization method in the container (for example, InitializingBean. AfterPropertiesSet (), or any statement of the init () method) is called before and after any Bean initialization callback will get a callback methods. The post-processor will do anything with the Bean instance, including completely ignoring callbacks. A Bean post-processor usually checks the callback interface or wraps a Bean through a proxy. Some Spring AOP base classes use a post-processor approach to provide proxy logic.
ApplicationContext will automatically infer that beans that implement the BeanPostProcessor interface and are defined in the configuration metadata will be registered in the container and will be called when the Bean is created. BeanPostProcessor can be deployed in a container just like a normal Bean.
When you declare BeanPostProcessor in a configuration class using the @bean annotation, be sure to set the return value to either the class itself or, at least for the BeanPostProcessor interface, to explicitly state the “post-processor properties” of the Bean. Otherwise, ApplicationContext cannot infer the BeanPostProcessor from type recognition until it is fully created. This is important because the BeanPostProcessor needs to be instantiated earlier to handle the instantiation of other beans.
Note: Register the BeanPostProcessor programmatically. The recommended way to register is to automatically infer from the ApplicationContext, but you can also do so using the addBeanPostProcessor method of the ConfigurableBeanFactory. This approach is useful when you need to evaluate the conditional environment logic before registration and copy the Bean processor between inherited containers. However, this method does not specify the order of execution. In addition, the registered post-processor must be executed before the automatically inferred registered processor.
The classes that implement the BeanPostProcessor interface are special, and the container handles them differently. As part of the special startup phase of the ApplicationContext, all The BeanPostProcessor instances and beans that they directly reference are instantiated at startup. Next, all BeanPostProcessor instances are registered in sort and applied to all other beans in the container. Because THE AOP automatic proxy is implemented as the BeanPostProcessor itself, neither The BeanPostProcessor instances nor the beans they directly reference are eligible for automatic proxy, so there are no woven aspects.
For beans injected using the @Autowired annotation, Spring might look for them by type, but it might find some unexpected beans that might not qualify for automatic proxy or post-processing.
Next, look at an example using BeanPostProcessor:
package scripting;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
// simply return the instantiated bean as-is
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean; // we could potentially return any object reference here...
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
returnbean; }}Copy the code
Spring attached RequiredAnnotationBeanPostProcessor values into attributes in allow the annotation of the above at the same time, also allows the use of characteristics of the post-processor.
Customize the configuration metadata through BeanFactoryPostProcessor
BeanFactoryPostProcessor differs from BeanPostProcessor in that it operates at the configuration metadata level, It can read configuration metadata and change beans of type BeanFactoryPostProcessor before the IOC container instantiates them, as shown in Figure 2
Look at the definition:
public interface BeanFactoryPostProcessor {
// Modify the application context's internal bean factory after its standard initialization.
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
}
Copy the code
You can set multiple BeanFactoryPostProcessors, and you can control the order of execution by setting the Order property. As with BeanPostProcessor, you must implement the Ordered interface.
It is also possible to use Bean instances in BeanFactoryPostProcessor, but it causes premature instantiation and violates the standard container life cycle, so it is not recommended.Copy the code
When a Bean factory post-processor is declared in the ApplicationContext. Spring executes it automatically. To apply for container configuration metadata changes, Spring provides a series of preliminary statement Bean factory after processor, for example: PropertyOverrideConfigurer and PropertySourcesPlaceholderConfigurer. You can also use a custom BeanFactoryPostProcessor, for example, by registering a custom property editor.
ApplicationContext automatically extrapolate beans deployed in containers that implement the BeanFactoryPostProcessor interface and use them as Bean factory postprocessors when appropriate. You can also deploy the Bean factory post-processor just as you would any other Bean.
Here’s an article that goes into more detail about the differences and uses of BeanPostProcessor and BeanFactoryPostProcessor.
Customize the initialization logic through FactoryBean
For itself is the object implementation factory org. Springframework. Beans. Factory. FactoryBean interface
Look at the definition:
public interface FactoryBean {
// A property name that can be set to BeanDefinition, which can be used to identify object types that cannot be inferred from the factory Bean class.
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
// Return an instance (possibly shared or independent) of the object managed by this factory.
T getObject(a) throws Exception;
// Return the type of object that this FactoryBean creates, or null if not known in advance.Class<? > getObjectType();// Is the object managed by this factory a singleton? That is, will getObject() always return the same object (a reference that can be cached)?
default boolean isSingleton(a) {
return true; }}Copy the code
FactoryBean is also an example of how you can plug and remove the Spring IOC container instantiation logic. If you are writing complex rather than redundant XML configurations, you may want to consider using FactoryBeans to build or implement initialization logic.
The Spring framework makes heavy use of this interface, which comes with 50+ classes. When you want to get an instance of FactoryBean instead of the Bean it produces, just add an ‘&’ hyphen before the arguments to the getBean() method. For example, for a FactoryBean whose ID is “myBean”, just do getBean(“&myBean”) to get a FactoryBean instance.
Annotation-based container configuration
Is annotation-based configuration better than XML configuration? Spring’s answer is that it depends on actual usage, and there are pros and cons to both.
@Required
The @required annotation is used to set the Bean properties, for example:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
Copy the code
As indicated above, this property must be filled in during configuration, either by setting its value explicitly at Bean definition time or by weaving its value automatically.
Note: this property is not recommended to use, after Spring5.1 to want to force the filling value, consider using a constructor injection or InitializingBean afterPropertiesSet () injection.
Use the @autowired
This annotation can be used for the constructor, as shown below
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Copy the code
After Spring Framework4.3, this annotation can be omitted if there is only one constructor for the Bean definition, but if there is more than one, this annotation needs to be added to indicate which constructor should be used.
Of course, @autowired can also be used with traditional setter methods, such as:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
Copy the code
It can also be applied to methods with any name, and any number of arguments:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Copy the code
Or, apply to private fields and constructors:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
private MovieCatalog movieCatalog;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Copy the code
You can make Spring use ApplicationContext to inject all beans of this type by adding them to the array form:
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
Copy the code
For sets, we can also use this:
public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
Copy the code
Mapping is also possible, but the mapping key must be String, which represents the Bean name:
public class MovieRecommender {
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
Copy the code
@autoWired must have an injectable Bean by default, but the required attribute allows “optional” injection:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired(required = false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
Copy the code
Given Spring’s special constructor algorithm, @Autowired’s required property may be slightly different in the constructor or factory method parameters. For example, for scenarios where there is only one constructor, such as arrays, sets, and maps, these can be empty instances even though @Autowired defaults to mandatory injection. This is possible for scenarios where all dependencies are declared in a single multi-parameter constructor.
Of course, we can also use JDK8 java.ugi. Optional for “Optional” injection:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder) {... }}Copy the code
With Spring Framework5.0, you can also use @nullable to indicate “non-mandatory” injection:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {... }}Copy the code
This annotation can also be used for well-known resolvable dependencies: The BeanFactory, ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher MessageSource, a subclass of these classes will be automatically parsed, None of them require special startup Settings:
public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender(a) {}// ...
}
Copy the code
Note: @autowired, @inject, @value, and @Resource cannot be used by BeanPostProcessor because BeanPostProcessor is the class that handles these annotations. So for your own BeanPostProcessor and BeanFactoryPostProcessor, you must explicitly register them through XML or @bean methods.
Use @Primary to fine-tune annotation-based automatic weaving
This approach is a bit broad for @Autowired based on type injection, so you need @Primary to figure out which of the many beans to choose is more appropriate. Such as:
@Configuration
public class MovieConfiguration {
@Bean
// MovieCatalog will be injected first.
@Primary
public MovieCatalog firstMovieCatalog(a) {... }@Bean
public MovieCatalog secondMovieCatalog(a) {... }// ...
}
Copy the code
Use Qualifiers to fine-tune annotation-based automatic weaving
For a specific Bean injection, you can also use @Qualifier to do a specific injection: bind a value to the Bean. Here’s an example:
public class MovieRecommender {
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
// ...
}
Copy the code
The corresponding injection:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main") MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Copy the code
For alternative matches, generally the Bean name defaults to the matching value, but sometimes this is not applicable, so you should identify yourself with specific values such as “main”, “EMEA”, “persistent”.
For collection types, @Qualifier can act as a filter, for example, to filter beans with specific names from a set of alternatives.
In the absence of other resolution indicators, Spring matches the name of the injection point (the property name) with the Bean name.
If you just want to filter by name and not by type, try @Resource. The difference between @Autowired and @Autowired is that @Autowired takes the type match first and then the name match first, so the type is less of a mandatory match.
Given the @Resource matching algorithm, using @Resource for name matching is a good choice for beans that are themselves maps or arrays. Of course, for @Autowired, make sure that the return type is consistent or that the return type inherits from the same parent, and then use a unique “value” attribute to indicate that.
Calling its @bean in a configuration class gives the result to another method, a form of “self-reference.” This is not recommended. One solution is to declare the @bean method static to avoid mixing it with the lifecycle of the configuration class. Or delay its parsing. Otherwise, set them in different configuration classes, and try not to be in the same configuration.
@Autowired works with private fields, constructors, and multi-parameter methods, allowing injection to be fine-grained using unique identifiers at the parameter stage. By contrast, @Resource only supports private domain and single-parameter setter methods for Bean properties. So, if you want to inject constructors or multi-parameter methods, be sure to use @qualifier for unique injection.
Of course, you can create your own qualifier annotation by simply providing @qualifier:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
String value(a);
}
Copy the code
Then you can use it like this:
public class MovieRecommender {
@Autowired
@Genre("Action")
private MovieCatalog actionCatalog;
private MovieCatalog comedyCatalog;
@Autowired
public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
this.comedyCatalog = comedyCatalog;
}
// ...
}
Copy the code
Sometimes a qualifier without a name is fine, and they match by type by default.
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
Copy the code
Use:
public class MovieRecommender {
@Autowired
@Offline
private MovieCatalog offlineCatalog;
// ...
}
Copy the code
Of course, you can also set more than one property, all of which must be matched when matching.
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {
String genre(a);
Format format(a);
}
public enum Format {
VHS, DVD, BLURAY
}
Copy the code
In use, it must satisfy:
public class MovieRecommender {
@Autowired
@MovieQualifier(format=Format.VHS, genre="Action")
private MovieCatalog actionVhsCatalog;
@Autowired
@MovieQualifier(format=Format.VHS, genre="Comedy")
private MovieCatalog comedyVhsCatalog;
@Autowired
@MovieQualifier(format=Format.DVD, genre="Action")
private MovieCatalog actionDvdCatalog;
@Autowired
@MovieQualifier(format=Format.BLURAY, genre="Comedy")
private MovieCatalog comedyBluRayCatalog;
// ...
}
Copy the code
Use generics as an automatic woven qualifier
You can use generic types as unique identifiers, such as the following Bean definition:
@Configuration
public class MyConfiguration {
@Bean
public StringStore stringStore(a) {
return new StringStore();
}
@Bean
public IntegerStore integerStore(a) {
return newIntegerStore(); }}Copy the code
Then you can use it like this:
@Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
@Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean
Copy the code
Of course, generic identifiers can also be used for List, Map instances, and arrays:
// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@Autowired
private List<Store<Integer>> s;
Copy the code
Using CustomAutowireConfigurer
CustomAutowireConfigurer is a BeanFactoryPostProcessor that lets you register your own custom Qualifier annotation types, even if they are not annotated using Spring’s @Qualifier annotation. Here’s a usage:
<bean id="customAutowireConfigurer"
class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>example.CustomQualifier</value>
</set>
</property>
</bean>
Copy the code
Use @Resource for the injection
Spring also supports the use of @ javax.mail. The annotation. The Resource of private domain or Bean property setter methods for injection.
@Resource comes with a name attribute, which Spring interprets as the Bean name by default. It works when injecting by name:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder")
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder; }}Copy the code
If you do not specify the value of the name property, the default is the name of the private field property to be injected or the name of the setter parameter. And in this case, something like @autowired, like:
public class MovieRecommender {
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context;
public MovieRecommender(a) {}// ...
}
Copy the code
For the above injection, a Bean named “customerPreferenceDao” will be sought first. If not, a Bean of type customerPreferenceDao will be sought (as a type match).
Using the @ Value
@value is usually used to inject extrinsic properties, that is, properties that are written in configuration files. Here’s an example:
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("${catalog.name}") String catalog) {
this.catalog = catalog; }}Copy the code
With the following configuration classes:
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {}Copy the code
The configuration file is as follows:
catalog.name=MovieCatalog
Copy the code
Spring provides a loose value resolver, and if the desired value is not found, the property name is injected as the default. However, you can customize a PropertySourcesPlaceholderConfigurerBean for more strict control:
@Configuration
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer(a) {
return newPropertySourcesPlaceholderConfigurer(); }}Copy the code
Note that when statement PropertySourcesPlaceholderConfigurerBean method must be static.
The above measures ensure failure if the placeholder is not found, however, placeholders can also be defined via setsummarize prefix (), setsuffix (), and setValueSeparator().
Spring Boot provides a default implementation PropertySourcesPlaceholderConfigurer to load from the application. The properties and application. The yml file attributes.
Spring also provides built-in conversions to basic types, as well as the ability to convert property values based on comma ‘,’ delimiters to String arrays.
Of course, you can also set the default values as follows:
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
this.catalog = catalog; }}Copy the code
A Spring BeanPostProcessor uses the built-in ConversionService to convert property values to the required type, so you can implement your own ConversionService to do the conversion:
@Configuration
public class AppConfig {
@Bean
public ConversionService conversionService(a) {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new MyCustomConverter());
returnconversionService; }}Copy the code
When @value contains a SpEL expression, the Value of the property is evaluated dynamically at runtime:
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
this.catalog = catalog; }}Copy the code
SpEL includes support for more complex data structures:
@Component
public class MovieRecommender {
private final Map<String, Integer> countOfMoviesPerCatalog;
public MovieRecommender(
@Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
this.countOfMoviesPerCatalog = countOfMoviesPerCatalog; }}Copy the code
Use @postConstruct and @PreDestroy
Javax.mail. The annotation. PostConstruct and javax.mail. The annotation. PreDestroy can be CommonAnnotationBeanPostProcessor scanning to and processing of the life cycle, as shown below:
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache(a) {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearMovieCache(a) {
// clears the movie cache upon destruction...}}Copy the code
Path scanning and component management
The previous sections focused on using XML for Bean definition and Bean registration. Although the previous chapter covered using annotations for source-level Bean definition and registration, that was just dependency injection. The definition of the “base Bean” and the assembly of the underlying components still had to be done in the XML file. So, this chapter shows you how to use the filtering mechanism to infer the underlying configuration classes and register them with the container to complete Bean assembly (in effect, how to get rid of XML entirely and use pure Java code configuration).
@Component and Stereotype annotations
@repository is an annotation used to annotate DAO components, usually with exception translation responsibilities.
Spring provides several template annotations: @Component, @Service, and @Controller. @Component is also often annotated as a generic template for any spring-managed Component. @Repository, @Service, and @Controller are all specialized @Component for more specific scenarios (such as persistence, Service, presentation, etc.). @Component is suitable for general scenarios. So, you can decorate your class with @Component, but you can also decorate your class with the special beans mentioned above, which will make your class more focused on specific business processes. So if you can use more specific annotations, don’t use @Component
package org.springframework.stereotype;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
String value(a) default "";
}
Copy the code
Inheritance hierarchy:
Use meta-annotations and composite annotations
Spring provides some annotations that can be used as meta-annotations in your code. Meta-annotations are annotations that can be applied to other annotations. For example, @Component is a meta-annotation:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
// ...
}
Copy the code
You can also create “composite annotations” with composite meta-annotations, such as the @RestController in Spring MVC which is a composite annotation for @Controller and @responseBody. Composite annotations can override the properties of meta-annotations, which is useful because in this way you can define only a subset of the properties of the parent annotations and give default values for the others. Such as:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_SESSION)
public @interface SessionScope {
/**
* Alias for {@link Scope#proxyMode}.
* <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
*/
@AliasFor(annotation = Scope.class)
ScopedProxyMode proxyMode(a) default ScopedProxyMode.TARGET_CLASS;
}
Copy the code
ProxyMode can then be used without declaring proxyMode:
@Service
@SessionScope
public class SessionScopedService {
// ...
}
Copy the code
You can specify proxyMode:
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
public class SessionScopedUserService implements UserService {
// ...
}
Copy the code
About the proxyMode property:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
/** * Specifies whether a component should be configured as a scoped proxy * and if so, whether the proxy should be interface-based or subclass-based. * Defaults to ScopedProxyMode.DEFAULT, which typically indicates * that no scoped proxy should be created unless a different default * has been configured at the component-scan instruction level. * Analogous to
support in Spring XML. */
ScopedProxyMode proxyMode(a) default ScopedProxyMode.DEFAULT;
}
Copy the code
Automatically inferring class and registering Bean definitions
Spring can automatically infer template classes and register corresponding Bean definition instances with the ApplicationContext. Such as:
@Service
public class SimpleMovieLister {
private MovieFinder movieFinder;
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder; }}Copy the code
@Repository
public class JpaMovieFinder implements MovieFinder {
// implementation elided for clarity
}
Copy the code
Both of the above classes meet the criteria for automatic inference.
To infer the component class correctly, you can add @ComponentScan to the @Configuration annotation by setting the value of the basePackages property, which is the parent package of the component class, and also based on ‘,'(comma),’; Multiple packages separated by ‘(semicolon), ‘ ‘(space). Such as:
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
// ...
}
Copy the code
Note: Sometimes, for brevity, it is possible to use the value property directly. The effect is the same: @componentScan (“org.example”)
Use filters to complete automated scans
By default, @Component, @Repository, @Service, @Controller, @Configuration, or any class declared by your custom annotation, can only infer candidate components. However, you can accomplish more complex filters by applying custom filters, using the includeFilters and excludeFilters properties of @ComponentScan to look at a table:
Filter type | Examples of expressions | describe |
---|---|---|
annotation | org.example.SomeAnnotation | Annotations for rendering or meta-rendering at the type level of the target component |
assignable | org.example.SomeClass | A class (or interface) that the target component can assign (extend or implement). |
aspectj | org.example.. *Service+ | An expression of type AspectJ that matches the target component |
regex | org\.example\.Default.* | A regular expression that matches the target component class name |
custom | org.example.MyTypeFilter | A for org. Springframework. Core. The custom implementations of the TypeFilter interface |
The following example shows ignoring all @repository annotated components and using the “stub” persistence layer instead:
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {... }Copy the code
Define the Bean metadata in the component
Spring components can also add Bean definitions to the container by simply adding @Bean annotations to the @Configuration annotated class:
@Component
public class FactoryMethodComponent {
@Bean
@Qualifier("public")
public TestBean publicInstance(a) {
return new TestBean("publicInstance");
}
public void doWork(a) {
// Component method implementation omitted}}Copy the code
The above class has application-specific code — the code in the body of the doWork() method. It also has a factory-like publicInstance() method that gives the Bean definition, and any annotation that is applied to a method can be used to qualify such a method, except that it can be Qualifier. The Bean name defaults to the method name.
Auto-woven domains and methods can also be used:
@Component
public class FactoryMethodComponent {
private static int i;
@Bean
@Qualifier("public")
public TestBean publicInstance(a) {
return new TestBean("publicInstance");
}
// use of a custom qualifier and autowiring of method parameters
@Bean
protected TestBean protectedInstance(
@Qualifier("public") TestBean spouse,
@Value("#{privateInstance.age}") String country) {
TestBean tb = new TestBean("protectedInstance".1);
tb.setSpouse(spouse);
tb.setCountry(country);
return tb;
}
@Bean
private TestBean privateInstance(a) {
return new TestBean("privateInstance", i++);
}
@Bean
@RequestScope
public TestBean requestScopedInstance(a) {
return new TestBean("requestScopedInstance".3); }}Copy the code
There is another way to complete the creation of a Bean by setting the InjectionPoint parameter to a factory method, which is useful for setting up a prototype Bean, only for the creation of Bean instances, not for the injection of existing instances.
The original:
As of Spring Framework 4.3, you may also declare a factory method parameter of type InjectionPoint (or its more specific subclass: DependencyDescriptor) to access the requesting injection point that triggers the creation of the current bean. Note that this applies only to the actual creation of bean instances, not to the injection of existing instances. As a consequence, this feature makes most sense for beans of prototype scope. For other scopes, the factory method only ever sees the injection point that triggered the creation of a new bean instance in the given scope (for example, the dependency that triggered the creation of a lazy singleton bean). You can use the provided injection point metadata with semantic care in such scenarios. The following example shows how to do use InjectionPoint:
@Component
public class FactoryMethodComponent {
@Bean
@Scope("prototype")
public TestBean prototypeInstance(InjectionPoint injectionPoint) {
return new TestBean("prototypeInstance for "+ injectionPoint.getMember()); }}Copy the code
The @Bean annotation is usually different from the other annotations in the @Configuration annotated class. The difference is that @Component does not support CGLIB interception of method and private field calls. CGLIB is a way to create a Bean metadata reference to a collaboration object by calling methods and private fields inside @Configuration’s @Bean method. This is not simply a Call in the Java syntax but rather, through the container to provide general full-lifecycle Bean management, proxies for Spring beans, and even programmatic calls to other @bean methods. By contrast, in the blank @Component decorated class, calling a method or field inside an @Bean method is only Java semantic, with no special CGLIB handling or constraints.
The original:
The @Bean methods in a regular Spring component are processed differently than their counterparts inside a Spring @Configuration class. The difference is that @Component classes are not enhanced with CGLIB to intercept the invocation of methods and fields. CGLIB proxying is the means by which invoking methods or fields within @Bean methods in @Configuration classes creates bean metadata references to collaborating objects. Such methods are not invoked with normal Java semantics but rather go through the container in order to provide the usual lifecycle management and proxying of Spring beans, even when referring to other beans through programmatic calls to @Bean methods. In contrast, invoking a method or field in a @Bean method within a plain @Component class has standard Java semantics, with no special CGLIB processing or other constraints applying.
Note:
You might declare @bean methods as static, which is fine because it means they can be called directly without instantiating the configuration class they contain. This is useful when defining post-processor beans (for example, BeanFactoryPostProcessor and BeanPostProcessor types) that are initialized early in the container life cycle without triggering the rest of the configuration.
Calls to static @bean methods are not intercepted by the container, even if configured in the @Configuration class, because CGLIB’s technical limitations mean that it can only intercept non-static methods. So, a call to the @bean method produces a direct Java semantic result — a new instance is generated and returned by the factory method.
The Java language’s visibility into @bean methods has no direct impact on the Spring container’s final Bean definition. You are free to declare any factory methods you want in non-@Configuration classes, or declare static methods anywhere you want. However, if the @bean method is declared in the @Configuration class, then the method should be overridden, that is, it cannot be private or final.
The @Bean method can also be scanned on the base class of a given component or configuration class and on the Java 8 default method declared in the interface implemented by the component or configuration class. This provides a lot of flexibility to combine complex configuration layouts, and even multiple inheritance through Java 8 default methods, starting with Spring 4.2.
Finally, a single class can hold multiple @bean methods, depending on the runtime dependencies, which in turn allow multiple factory methods to be used. This algorithm is the same as when configuring a class to select the “greediest” constructor and factory method: the one with the most satisfiable dependencies will be selected, similar to how a container selects the most appropriate constructor among multiple @AutoWired annotated constructors.
The original:
You may declare @Bean methods as static, allowing for them to be called without creating their containing configuration class as an instance. This makes particular sense when defining post-processor beans (for example, of type BeanFactoryPostProcessor or BeanPostProcessor), since such beans get initialized early in the container lifecycle and should avoid triggering other parts of the configuration at that point.
Calls to static @Bean methods never get intercepted by the container, not even within @Configuration classes (as described earlier in this section), due to technical limitations: CGLIB subclassing can override only non-static methods. As a consequence, a direct call to another @Bean method has standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.
The Java language visibility of @Bean methods does not have an immediate impact on the resulting bean definition in Spring’s container. You can freely declare your factory methods as You see fit in non-@Configuration classes and also For static methods anywhere. However, regular @bean methods in @configuration classes need to be overridable — that is, they must not be declared as private or final.
@Bean methods are also discovered on base classes of a given component or configuration class, as well as on Java 8 default methods declared in interfaces implemented by the component or configuration class. This allows for a lot of flexibility in composing complex configuration arrangements, with even multiple inheritance being possible through Java 8 default methods as of Spring 4.2.
Finally, a single class may hold multiple @Bean methods for the same bean, as an arrangement of multiple factory methods to use depending on available dependencies at runtime. This is the same algorithm as for choosing the “greediest” constructor or factory method in other configuration scenarios: The variant with the largest number of satisfiable dependencies is picked at construction time, analogous to how the container selects between multiple @Autowired constructors.
Name the component of automatic inference
When a Component is automatically inferred by the scanning process, its Bean name is generated by the BeanNameGenerator policy known to the scanner. By default, @Component, @repository, @Service, @controller The value specified in the value property of these annotations is used as the Bean name.
If this property is not specified, the Bean name defaults to a lower-case class name.
You can also customize your own BeanNameGenerator to set your own naming policy, and don’t forget to add a no-parameter constructor. Look at the definition of BeanNameGenerator:
public interface BeanNameGenerator {
/**
* Generate a bean name for the given bean definition.
* @param definition the bean definition to generate a name for
* @param registry the bean definition registry that the given definition
* is supposed to be registered with
* @return the generated bean name
*/
String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}
Copy the code
If in order to resolve the name of the class conflict (i.e., different package name class), you can use FullyQualifiedAnnotationBeanNameGenerator to handle, look at the definition:
public class FullyQualifiedAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {
@Override
protected String buildDefaultBeanName(BeanDefinition definition) { String beanClassName = definition.getBeanClassName(); Assert.state(beanClassName ! =null."No bean class name set");
returnbeanClassName; }}Copy the code
In general, though, it’s easier to define a Bean by its name, or if the Bean is woven through a container, the BeanNameGenerator is a good way to do it.
Provides scope for automatically inferred components
Spring container-managed beans are typically singletons. If you want to Scope your Bean definition, you can add the @scope annotation and specify its value attribute. Such as:
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
Copy the code
Note that @Scope only works on concrete Bean classes, or factory methods (methods that are decorated by @Bean), and has no inheritance hierarchy.
Of course, you can also customize Scope annotations by simply combining the meta-annotations provided by Spring, for example by combining @Scope with the proxy pattern.
To provide a custom scoping solution, you can implement the ScopeMetadataResolver interface. See the definitions:
public interface ScopeMetadataResolver {
/ * * *@param definition the target bean definition
* @return the relevant scope metadata; never {@code null}
*/
ScopeMetadata resolveScopeMetadata(BeanDefinition definition);
}
public class ScopeMetadata {
private String scopeName = BeanDefinition.SCOPE_SINGLETON;
private ScopedProxyMode scopedProxyMode = ScopedProxyMode.NO;
/** * Set the name of the scope. */
public void setScopeName(String scopeName) {
Assert.notNull(scopeName, "'scopeName' must not be null");
this.scopeName = scopeName;
}
/** * Get the name of the scope. */
public String getScopeName(a) {
return this.scopeName;
}
/** * Set the proxy-mode to be applied to the scoped instance. */
public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) {
Assert.notNull(scopedProxyMode, "'scopedProxyMode' must not be null");
this.scopedProxyMode = scopedProxyMode;
}
/** * Get the proxy-mode to be applied to the scoped instance. */
public ScopedProxyMode getScopedProxyMode(a) {
return this.scopedProxyMode; }}Copy the code
When using a non-singleton scope, you should provide a proxy for scoped objects. In this case, set @ComponentScan’s scopedProxy property. Optional values are: ScopedProxyMode INTERFACES, ScopedProxyMode. NO, ScopedProxyMode. TARGET_CLASS, for example, the following is an example of a standard enabled the JDK dynamic proxy:
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
// ...
}
Copy the code
Provide Qualifier metadata using annotations
As discussed earlier, @Qualifier can provide more granular control, but the metadata for those qualifiers is provided on the Bean definition, so for a path-scan based approach, you can provide the type level Qualifier metadata on the candidate classes, as shown below:
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
}
Copy the code
Note: The qualifier metadata on the component class in the path-based scan configuration cannot be shared, unlike the configuration with XML.
Generate an index of the alternative components
If the classpath scan is quick, do it directly at startup, for example by creating a static list of alternatives. To do this, you need to import the Spring-Context-Indexer package.
Remember to register the Spring-Context-Indexer as an annotation handler.
Use jSR-330 standard annotations
Use @inject and @named for dependency injection
Standard equivalencies for @Component: @named and @ManagedBean
Limitations of jSR-330 standard annotations
The next article
Can you give me a few bucks if you think it helps? (A little money for a lot of fun!)