Spring’s importance to every Java programmer is self-evident. However, for the development of Spring annotation programming, I believe there are a lot of partners are still not clear, this article will thoroughly comb for you.

The evolution of Spring annotation programming

1 Spring 1.x

Spring1.0 was released on March 24, 2004, providing IoC, AOP, and XML configuration methods.

Spring1.x provides a pure XML configuration, which means that in this version we must provide an XML configuration file in which we configure the beans to be managed by the IoC container through the

tag.


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean class="com.bobo.demo01.UserService" />
</beans>
Copy the code

Debugging code

public static void main(String[] args) {
    ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:applicationContext01.xml");
    System.out.println("ac.getBean(UserService.class) = " + ac.getBean(UserService.class));
}
Copy the code

The output

When Spring1.2 version provides @ Transaction (org. Springframework. Transaction. The annotation) annotations. Simplifies the operation of transactions.

2 Spring 2.x

Spring2.0 was released on October 3, 2006. In the 2.x release, a significant feature was the addition of many annotations

Spring 2.5 before

@Required @repository @aspect was added prior to version 2.5, and also extended XML configuration capabilities to provide third-party extension tags such as

@Required

If you use this comment on a set method of a Java class, then the corresponding property of the set method must be set in the XML configuration file or an error will be reported!!

public class UserService {


    private String userName;

    public String getUserName(a) {
        return userName;
    }

    @Required
    public void setUserName(String userName) {
        this.userName = userName; }}Copy the code

If we do not set the corresponding attribute in the XML file, it will give an error message.

After setting the properties, there are no errors

You can see in the source code that @Required is available from 2.0 onwards

@Repository

@repository corresponds to the data access layer Bean. This annotation is provided in Spring2.0, which you may not expect.

@Aspect

The @aspect is an AOP-related annotation that identifies configuration classes.

After the spring

On November 19, 2007, Spring was updated to version 2.5, which added a number of common annotations and greatly simplified configuration operations.

annotations instructions
@Autowired Dependency injection
@Qualifier Configure the @autoWired annotation to use
@Component Announcement component
@Service Declare business layer components
@Controller Declare control layer components
@RequestMapping Declare the processing method corresponding to the request

With these annotations, we don’t need to register the bean in the XML file. In this case, we just need to specify the scan path and add the corresponding annotation in the bean header, which greatly simplifies our configuration and maintenance work. Here are some examples:

We only need to configure the scan code path in the configuration file:


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.bobo" />

</beans>
Copy the code

Persistence layer code:

@Repository
public class UserDao {

    public void query(a){
        System.out.println("dao query ..."); }}Copy the code

Business logic layer code

@Service
public class UserService {

    @Autowired
    private UserDao dao;

    public void query(a){ dao.query(); }}Copy the code

Control layer code:

@Controller
public class UserController {

    @Autowired
    private UserService service;

    public void query(a){ service.query(); }}Copy the code

The test code

public class Demo02Main {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext02.xml"); UserController acBean = ac.getBean(UserController.class); acBean.query(); }}Copy the code

Although the 2.5 release of Spring provided a lot of annotations and greatly simplified our development, it still didn’t get rid of the XML configuration driver.

3 Spring 3.x

Spring3.0, a milestone in the evolution of annotation programming, was released on December 16, 2009, embracing Java5 in full. The @Configuration annotation is provided to de-XML. The @ImportResource also provides a mixture of Java configuration classes and XML configuration to smooth the transition.

/ * * *@ConfigurationThe Annotated Java classes are equivalent to the application.xml configuration file */
@Configuration
public class JavaConfig {

    / * * *@BeanThe annotation method is equivalent to the <bean></bean> tag, which is also provided by Spring3.0@return* /
    @Bean
    public UserService userService(a){
        return newUserService(); }}Copy the code

Before Spring3.1, we could only configure the scan path using the ComponentScan tag in the XML configuration file. Before 3.1, we could not fully implement the dexml configuration. When 3.1 came, we provided a @componentscan annotation. This annotation, which replaces the Component-Scan tag, is a big step forward in annotation programming and a solid foundation for Spring’s configuration-free implementation.

@ComponentScan

The @componentScan is used to specify the scan path instead of the < Component-scan > tag in XML. The default scan path is the package and subpackages of the annotated class.

Define the UserService

@Service
public class UserService {}Copy the code

Create a Java configuration class for

@Configuration
@ComponentScan
public class JavaConfig {

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
        System.out.println("ac.getBean(UserService.class) = "+ ac.getBean(UserService.class)); }}Copy the code

Output result

You can also specify a specific scan path

@Configuration
// Specify a specific scan path
@ComponentScan(value = {"com.bobo.demo04"})
public class JavaConfig {

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
        System.out.println("ac.getBean(UserService.class) = "+ ac.getBean(UserService.class)); }}Copy the code

@Import

The @import annotation can only be used on classes and is used to quickly Import instances into Spring’s IoC container. There are many ways to Import instances into the IoC container, such as the @bean annotation. The @import annotation can be used to Import third-party packages. There are three ways to use it.

Static imports

The static import method is to directly add the object types that we need to import into the IoC container.

The advantage of this way is simple, direct, but the disadvantage is that if you want to import more, it is not very convenient, but also not flexible.

ImportSelector

In the @import annotation we can also add a type that implements the ImportSelector interface. Instead of importing the type into the IoC container, we will call selectImports defined in the ImportSelector interface. Adds the type of the array of strings returned by this method to the container.

Define two business classes

public class Cache {}public class Logger {}Copy the code

Define the implementation of the ImportSelector interface. The method returns a full classpath array of strings for the types of objects that need to be added to the IoC container. We can import different types according to different business needs, which will be more flexible.

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return newString[]{Logger.class.getName(),Cache.class.getName()}; }}Copy the code

Importing test Cases

@Configuration
@Import(MyImportSelector.class)
public class JavaConfig {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
        for (String beanDefinitionName : ac.getBeanDefinitionNames()) {
            System.out.println("beanDefinitionName = "+ beanDefinitionName); }}}Copy the code

Output results:

ImportBeanDefinitionRegistrar

Besides the introduction of flexible ImportSelector import above also provides ImportBeanDefinitionRegistrar interface, can be achieved, Compared ImportSelector interface, ImportBeanDefinitionRegistrar way is directly in the definition of method provides BeanDefinitionRegistry, register yourself in a method implementation.

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // Encapsulate the object to be registered as a RootBeanDefinition object
        RootBeanDefinition cache = new RootBeanDefinition(Cache.class);
        registry.registerBeanDefinition("cache",cache);

        RootBeanDefinition logger = new RootBeanDefinition(Logger.class);
        registry.registerBeanDefinition("logger",logger); }}Copy the code

The test code

@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class JavaConfig {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
        for (String beanDefinitionName : ac.getBeanDefinitionNames()) {
            System.out.println("beanDefinitionName = "+ beanDefinitionName); }}}Copy the code

The output

@EnableXXX

Enable Module driver. In fact, in the system, we first develop modules with independent functions, such as Web MVC module, AspectJ agent module, Caching module, etc.

Example: Define the function module first

/** * define a Java configuration class
@Configuration
public class HelloWorldConfiguration {

    @Bean
    public String helloWorld(a){
        return "Hello World"; }}Copy the code

Then define the @enable annotation

/ * * * definition@EnableThe annotation * is passed in this annotation@ImportThe annotations import our custom module to make it work. * /
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}
Copy the code

The test code

@Configuration
// Load the custom module
@EnableHelloWorld
public class JavaMian {

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaMian.class);
        String helloWorld = ac.getBean("helloWorld", String.class);
        System.out.println("helloWorld = "+ helloWorld); }}Copy the code

The effect

4 Spring 4.x

Spring 4.0, updated November 1, 2013, fully supports Java8. This is an era of annotation perfection, providing the core annotation is @conditional Conditional annotation. The @conditional annotation is used to make a judgment based on certain conditions, and then registers the Bean instance with the container.

@conditional is defined as:

// This annotation can be used in classes and methods
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	The type added to the annotation must be the type that implements the Condition interface */
	Class<? extends Condition>[] value();

}
Copy the code

Condition is an interface that needs to implement the matches method, which returns true if the bean is injected, and false if it is not.

Case study:

/** * Defines a Condition interface by implementing */
public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false; // Return false by default}}Copy the code

Create a Java configuration class

@Configuration
public class JavaConfig {

    @Bean
    // The type to be added must be the type that implements the Condition interface
    // MyCondition's matches method returns true if it is injected, and false if it is not
    @Conditional(MyCondition.class)
    public StudentService studentService(a){
        return new StudentService();
    }

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
        for (String beanDefinitionName : ac.getBeanDefinitionNames()) {
            System.out.println("beanDefinitionName = "+ beanDefinitionName); }}}Copy the code

Testing:

Setting the return of the matchs method to true has a different effect

So the role of @Conditional is to provide a Conditional mechanism for objects to be imported into the IoC container, which is the core of the automatic assembly in SpringBoot. Of course, 4.x also provides some other annotation support, such as @EventListener, which, as a second choice for the ApplicationListener interface programming, @Aliasfor removes the constraint on annotation derivation conflicts. CrossOrigin as a solution for cross-domain resources in browsers.

5 Spring 5.x

On September 28, 2017, Spring arrived in version 5.0. 5.0 is also the base of SpringBoot2.0. The performance improvement aspect of annotation-driven is not obvious. In Spring Boot application scenarios, @ComponentScan scan is widely used, resulting in an increase in the parsing time of Spring pattern annotations. Therefore, in the 5.0 era, ** @indexed ** was introduced to add indexes to Spring pattern annotations.

After we use @indexed in the project, the META-INT/spring.components file is automatically generated in the project when the packaging is compiled. When the Spring application context execute ComponentScan scanning, META-INT/spring.com ponents will be CandidateComponentsIndexLoader read and loaded, Convert to the CandidateComponentsIndex object, so that @ComponentScan does not scan the specified package, but reads the CandidateComponentsIndex object, thus improving performance.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-indexer</artifactId>
</dependency>
Copy the code

Use the @indexed annotation

Well, to this I believe you should be more clear about the development process of Spring, if it is helpful to you, welcome to focus on zan plus collection!!