Spring uses annotations to store Bean objects


In the previous blog ( Spring Project Creation and Bean Storage and Reading (DL) ), it was introduced to register objects through configuration files and store them in Spring. This method is actually quite cumbersome.

In fact, in the process of using and learning to use Spring, when we want to implement a function, we should first consider whether there are corresponding annotations to realize the corresponding function. The configuration of many functions in Spring can be realized by annotations. This article introduces the use of annotations to store Bean objects.

1. Configure the scan path

First of all, we still need to create a Spring project. If there is a problem here, go to my last blog. After creating the project, our first step is to configure the scanning path. This step is very critical. If it is wrong here, the subsequent operations will not take effect.

We resourcescreate a spring-config.xmlconfiguration file in the directory to set the scanning path, and add the following content to the configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="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 https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package=""></content:component-scan>
</beans>

The value inside is set to the root path of the object you need to scan. This path starts from the directory. For example, I create a class in the directory shown in the figure <content:component-scan base-package=""></content:component-scan>: then the root path in this configuration file is , so we set the value of .base-packagejavacom.tr.demo
img
com.tr.demobase-packagecom.tr.demo

<content:component-scan base-package="com.tr.demo"></content:component-scan>

2. Use annotations to store Bean objects

If you want to use annotations, you must first know which annotations can be used. There are five types of annotations and method annotations in Spring, which are:

  1. Five categories of annotations: @Controller (controller), @Service (service), @Repository (warehouse), @Component (component), @Configuration (configuration).
  2. Method annotation: @Bean.

1. Use five types of annotations to store beans

First, let's understand how to use the five types of annotations to store objects. Taking @Controllerannotations as an example, we have the following code:

package com.tr.demo;

import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    
    
    public void sayHi() {
    
    
        System.out.println("Hi, UserController~");
    }
}

Create a class under the scanning path like this, and add @Controllerannotations to the class to Beanstore it in the container.

The next step is to read our objects from Spring. Here we still use the method of dependency lookup to obtain beans, using five types of annotations. By default, the name of the bean is the original class name in lowercase (small hump).

import com.tr.demo.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class APP {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        //获取对象时使用类名的小驼峰形式作为 name 参数
        UserController userController =  context.getBean("userController", UserController.class);
        userController.sayHi();
    }
}

Running results:
img
Note that the classes created using the five major types of annotations must be in the scanning path we configured earlier (including subpackages) to store beans in Spring, otherwise it is invalid, so this scanning path also called the root path.

Setting the root path is actually to improve the performance of the program, because if you do not set the root path, Spring will scan all the directories in the project file, but not all classes need to be stored in Spring, so the performance will be relatively low, set Root path, Spring only scans all the directories under the root path, which improves the performance of the program.

Only @Controller is used above, so let’s verify that the other four annotations can achieve the same purpose. At the same time, in order to verify the above conclusion, we com.tr.democreate another innerdirectory under the directory and create a class outside the root path Studentusing class annotations .

img

package com.tr.demo.inner;
import org.springframework.stereotype.Component;

@Component
public class UserComponent {
    
    
    public void sayHi() {
    
    
        System.out.println("Hi, UserComponent~");
    }
}

package com.tr.demo.inner;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfiguration {
    
    
    public void sayHi() {
    
    
        System.out.println("Hi, UserConfiguration~");
    }
}

package com.tr.demo.inner;
import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {
    
    
    public void sayHi() {
    
    
        System.out.println("Hi, UserRepository~");
    }
}

package com.tr.demo.inner;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    
    
    public void sayHi() {
    
    
        System.out.println("Hi, UserService~");
    }
}

import com.tr.demo.UserController;
import com.tr.demo.inner.UserComponent;
import com.tr.demo.inner.UserConfiguration;
import com.tr.demo.inner.UserRepository;
import com.tr.demo.inner.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class APP {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        //获取对象时使用类名的小驼峰形式作为 name 参数
        UserController userController =  context.getBean("userController", UserController.class);
        userController.sayHi();
        UserService service =  context.getBean("userService", UserService.class);
        service.sayHi();
        UserConfiguration configuration =  context.getBean("userConfiguration", UserConfiguration.class);
        configuration.sayHi();
        UserComponent component =  context.getBean("userComponent", UserComponent.class);
        component.sayHi();
        UserRepository repository =  context.getBean("userRepository", UserRepository.class);
        repository.sayHi();
    }
}

operation result:

The effects of the five categories of annotations are the same, and those not under the root path Studentare invalid.
img

What also needs to be known is that the beans stored using annotations and XMLthe beans stored using annotations can be used together. For example, we will store the Studentre-passed method that just had a problem.XML

img

operation result:

img

2. Why are there five types of annotations?

Since the five major categories complete the same work, why are there five major categories of annotations?

In fact, the five major categories of annotations are mainly to standardize the code of Java projects. The standard layers of Java projects are as follows:

  1. Control layer (Controller)
  2. Service Layer (Service)
  3. Data persistence layer (Dao)

The five categories of annotations are used corresponding to different layer levels, so that programmers can see what a certain annotation does to clarify what the class does.

  • @Controller: The controller, which verifies the correctness of the data requested by the user (security system); directly deals with the front-end, and verifies the parameters and legality of the request sent by the front-end.

  • @Service: Service, orchestration and scheduling specific execution methods (customer service center); will not directly operate the database, and judge which method to call according to the request.

  • @Repository: The data persistence layer, which directly interacts with the database (execution of actual business), is also called the DAO layer (data access object).

  • @Component: Component (tool class layer), which stores some components that need to be used for the entire project, but has no actual interaction with other layers.

  • @Configuration configuration items (some configurations in the project).

img

Including enterprises, projects are also layered according to this structure. A typical example is Ali, which only expands the standard layer in the service layer (Service), and the division is more detailed.

img

The five categories of annotations mainly play the role of "seeing the name and knowing the meaning". From the code level, the functions are similar. Let's check the source code of the five categories of annotations.

img

img

img

img

img
It can be seen that in addition to @Component in the source code of the five major categories, the other four categories of annotations include the functions of @Component annotations. These four categories of annotations are all implemented based on @Component and are @Component extensions.

3.4 Naming rules for obtaining Bean parameters

When using the dependent lookup method above Bean, getBeanthe method BeanNameis to use the lowercase form of the class name (that is, the first letter of the class name is lowercase). This is because when using annotations to store objects, the lowercase form of the class name will be set by default. Bean's name, but not completely in accordance with this rule, there are special cases.

For example, we create a class and capitalize its first two letters. For example UConfig, at this time, we can see if the bean can be obtained by using the small camel case of the class name.

package com.tr.demo;

import org.springframework.stereotype.Repository;

@Repository
public class UConfig {
    
    
    public void sayHi(){
    
    
        System.out.println("Hi, UConfig~");
    }
}

startup class

import com.tr.demo.UConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class APP2 {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        UConfig uConfig=  context.getBean("uConfig", UConfig.class);
        uConfig.sayHi();
    }
}

Running result:
img
You can see that the program reported an error, saying that the object beanNamefor was not found uConfig, so beanNamewhat is it at this time?

At this point, try the original class name (big hump) to see if you can get it:

UConfig uConfig=  context.getBean("UConfig", UConfig.class);

Running result:
img
It is obtained at this time, it seems that there is a bit of metaphysics in it, let's look through the source code and see what is the reason for this.

Double-click Shiftto perform a global search. The above is to find the object based on the object name, so we enter beanNameand try to search:

img

We will find that there are AnnotationBeanNameGeneratorclasses and BeanNameGeneratorinterfaces, so let's try to click on AnnotationBeanNameGeneratorthe source code of the class to have a look.

After opening it normally, you should see .classthe code decompiled by IDEA, lacking comments and clear variable naming.

img

We Download Sourcescan click to download the Spring source code. At this time, we can see the following method in the source code, and we can also know the name, which is used to create the default one BeanName.

img

The return value is Introspector.decapitalizethe return value of the method, and then click in to see this method.

img

At this point, we can analyze and conclude that if the length of the class name is greater than that 1and the first and second letters are capitalized, then BeanNamethe original class name will be constructed, and in other normal cases, it will be the small hump form of the class name, which is Explains why UConfigthe class BeanNameis the original class name.
And we will find that the class where this method is from jdk.
img

Therefore, BeanNamethe canonical naming rules are not created by Spring, but are carried out in accordance with the rules of the Java standard library.

  1. If the class name does not exist or the class name is an empty string, BeanNameit is the original class name.
  2. If the length of the class name is greater than 1, and the first and second characters are uppercase, BeanNameit is the original class name.
  3. In other cases, BeanNameit is the lower camel case of the original class name.

3. Use method annotations to store Bean objects

1. Method annotation storage object usage

The five types of annotations are added to a certain class, and the method annotations are placed on the method. When a method returns a specific instance object, we can use the method annotation to store the object in Spring, but @Beanonly Using one @Beanis not enough to successfully store the object. It is also necessary to use five types of annotations on the class where the method is located. For example, with a @Component annotation, the method annotation cannot be used alone. The annotation must be used together with the five types of annotations @Bean( The regulations made by Spring to improve performance, after all, the cost of creating methods is too low to scan the method of the entire project).

It should still be noted that the use must be under the root path.

For example, we have an entity class of ordinary articlesArticleInfo

package com.tr.demo.model;

import java.time.LocalDateTime;

/**
 * 普通的文章实体类
 */
public class ArticleInfo {
    
    
    private int aid;
    private LocalDateTime createtime;
    private String title;
    private String author;
    private String content;
    
    public void setAid(int aid) {
    
    
        this.aid = aid;
    }
    public void setCreatetime(LocalDateTime createtime) {
    
    
        this.createtime = createtime;
    }
    public void setTitle(String title) {
    
    
        this.title = title;
    }

    public void setAuthor(String author) {
    
    
        this.author = author;
    }
    public void setContent(String content) {
    
    
        this.content = content;
    }

    @Override
    public String toString() {
    
    
        return "ArticleInfo{" +
                "aid=" + aid +
                ", createtime=" + createtime + "\n" +
                ", title='" + title + '\'' +
                ", author='" + author + '\'' + "\n" +
                ", content='" + content + '\'' +
                '}';
    }
}

The following demonstrates the use of @Beanmethod annotations to store objects

package com.tr.demo;

import com.tr.demo.model.ArticleInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import java.time.LocalDateTime;

@Controller
public class Articles {
    
    
    @Bean// 将当前方法返回的对象存储到 IoC 容器
    public ArticleInfo getArt(){
    
    
        // 伪代码(实际上这里的 Bean 不是 new 出来的)
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setAid(1);
        articleInfo.setCreatetime(LocalDateTime.now());
        articleInfo.setTitle("夏日绝句");
        articleInfo.setAuthor("李清照");
        articleInfo.setContent("生当做人杰,死亦为鬼雄。至今思项羽,不肯过江东。");
        return articleInfo;
    }

    public void sayHi(){
    
    
        System.out.println("Hi, Articles~");
    }
}

When obtaining the object stored in the method annotation, the default value of the parameter value passed in BeanNameis the method name. The method name in my code above getArt, so when obtaining it, use it getArtas a parameter to obtain it.

import com.tr.demo.model.ArticleInfo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class APP3 {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        ArticleInfo article =  context.getBean("getArt", ArticleInfo.class);

        System.out.println(article);
    }
}

operation result:
img

2. @Bean renaming

When obtaining the object stored in the method annotation, BeanNamethe default value of the parameter value passed in is the method name, but the method name that returns the object as above is often getXXXnamed in this way. Although there is no problem in syntax and implementation, the actual development Writing such code seems rather awkward.

In fact, the annotation @Bean can add parameters and alias the stored object, like the following.

@Controller
public class Articles {
    
    
    @Bean("article")// 将当前方法返回的对象存储到 IoC 容器
    public ArticleInfo getArt(){
    
    
        // 伪代码(实际上这里的 Bean 不是 new 出来的)
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setAid(1);
        articleInfo.setCreatetime(LocalDateTime.now());
        articleInfo.setTitle("夏日绝句");
        articleInfo.setAuthor("李清照");
        articleInfo.setContent("生当做人杰,死亦为鬼雄。至今思项羽,不肯过江东。");
        return articleInfo;
    }

    public void sayHi(){
    
    
        System.out.println("Hi, Articles~");
    }
}

You can also set multiple aliases for the Bean. In summary, there are several ways:

//方式一(省略参数名的情况下默认是name)
@Bean("article1")
//方式二
@Bean(name = "article2")
//方式三
@Bean(value = "article3")
//起多个别名
@Bean(name = {
    
    "article4", "article5"})
@Bean(value = {
    
    "article6", "article7"})
@Bean({
    
    "article8", "article9", "article10"})

We set it according to the method of line 9. At this time, the object stored in the method annotation can be obtained using the alias.

img

import com.tr.demo.model.ArticleInfo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class APP4 {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        ArticleInfo article1 =  context.getBean("article6", ArticleInfo.class);
        System.out.println(article1);
        System.out.println("-----------------------------------------------------");
        ArticleInfo article2 =  context.getBean("article7", ArticleInfo.class);
        System.out.println(article2);
        System.out.println("-----------------------------------------------------");
    }
}

operation result:
img

Think again, when a Bean has an alias, can the object be obtained by using the previous method name? try it:

import com.tr.demo.model.ArticleInfo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class APP5 {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        ArticleInfo article =  context.getBean("getArt", ArticleInfo.class);
        System.out.println(article);
    }
}

operation result:

At this time, you can find that it is not available.
img
So the naming rule for using @Bean to store objects beanNameis that when no name/valueattribute is set, the default name of the Bean is the method name. Once the alias attribute is added name/value, it can only be renamed The alias to obtain the Bean, the default use of the method name to obtain the Bean object cannot be used.

Also briefly note that when @Bean is used, if multiple beans of the same class use the same name, the program execution will not report an error at this time. It will be based on the order of class loading and the order of code in the class from top to bottom. Store the first bean in Spring, but the objects after the first will not be stored in the container, that is, only when the bean is created for the first time, the object will be associated with the bean name, and then there will be When the Bean with the same name is stored, the container will automatically ignore it.

You can also @Ordercontrol the class loading order through class annotations (the smaller the value, the higher the priority), and then affect the order in which beans are stored. These are relatively simple and will not be demonstrated.

Guess you like

Origin blog.csdn.net/Trong_/article/details/131816931
Recommended