Hello, I am silent king two, an interesting programmer, writing articles has been full of spirit, and strive to be fresh and refined. Yesterday, I went to the Xiao Mi store in Wangfujing and ordered a Mi 10, saying it would arrive in a week, but I still can’t help wanting to see her today. See my tea do not think rice do not want, the wife advised me to say, with its blind think, return not equal to roll to write your article. Thus came today’s “Common Configuration of Spring Beans”, in the form of a conversation between me and My sister.

Teaching younger girls to learn Java, have you ever seen such a cheeky title? Yes, the title of this article is so cool, otherwise why would you click on it?

I have a beautiful sister (pictured above). What is her name? I think smart readers can guess that the Silent King is, yes, 36 years old. Her parents are considering her to learn from me and become a serious Java programmer. I was against it at first, because the programmer industry is easy to lose hair. But it’s a tough family situation, so instead of fighting it, I could do something more positive, like write an interesting article to teach her.

“Brother, after I finished learning the basic chapter of Spring, I had a strong feeling that Spring is really strong, just like the Spring breeze Buddha’s face, like learning the next chapter.”

“Why, third sister, there is something poetic in your analogy, though it is far-fetched.”

“Ok, let’s begin today’s study!”

01, Bean Scope configuration

“Brother, it is said that there are several Scope types of Bean, which are used to define the life cycle and use environment of Bean. Could you give me more details?”

“No problem.”

1) the singleton

In the singleton pattern, defining a Bean’s Scope as a Singleton means that a Bean will only be created once in the Spring container, and any changes to that instance will be reflected in its references. This is also the default configuration item for Scope and can be omitted.

Create a new Writer class with the following contents:

public class Writer {
    private String name;

    public Writer(a) {}// getter setter
}
Copy the code

Create a new SingletonConfig class with the following contents:

@Configuration
public class SingletonConfig {
    @Bean
    @Scope("singleton")
    public Writer getWriterSingleton(a) {
        return newWriter(); }}Copy the code

The @Configuration annotation indicates that the current class is a Configuration class, equivalent to an XML file for Spring Configuration.

The @bean annotation is used on the getWriterSingleton() method to indicate that the current method returns a Bean object (Writer), which is then handed over to Spring for management.

We can replace the string singleton with a spring-defined constant:

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
Copy the code

Of course, you can omit it altogether, so SingletonConfig is slimmed down.

@Configuration
public class SingletonConfig {
    @Bean
    public Writer getWriterSingleton(a) {
        return newWriter(); }}Copy the code

Create a new SingletonMain class with the following code:

public class SingletonMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SingletonConfig.class);
        Writer writer1 = context.getBean(Writer.class);
        Writer writer2 = context.getBean(Writer.class);

        System.out.println(writer1);
        System.out.println(writer2);

        writer1.setName("Silent King II."); System.out.println(writer2.getName()); context.close(); }}Copy the code

The output of the program is as follows:

19 dc67c2 commonuse. Singleton. Writer @ commonuse. Singleton. 19 dc67c2 silence reigned two Writer @Copy the code

Writer1 and writer2 two object string representation are exactly the same, are commonuse. Singleton. The Writer @ dc67c2; In addition, if you change the name of the writer1 object, writer2 also changes.

From the results we can conclude that even though we get two Writer instances using getBean() when Scope is singleton, they are the same object. If you change the state of any one of them, the other will change as well.

2) prototype

Prototype means that a Bean creates multiple instances in Spring and is suitable for multithreaded scenarios.

Create a new PrototypeConfig class with the following content:

@Configuration
public class PrototypeConfig {
    @Bean
    @Scope("prototype")
    public Writer getWriterPrototype(a) {
        return newWriter(); }}Copy the code

We can use a spring-defined constant instead of the string prototype:

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Copy the code

Create a new PrototypeMain class as follows:

public class PrototypeMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrototypeConfig.class);
        Writer writer1 = context.getBean(Writer.class);
        Writer writer2 = context.getBean(Writer.class);

        System.out.println(writer1);
        System.out.println(writer2);

        writer1.setName("Silent King II."); System.out.println(writer2.getName()); context.close(); }}Copy the code

The output of the program is as follows:

commonuse.Writer@78a2da20
commonuse.Writer@dd3b207
null
Copy the code

The string representations for writer1 and writer2 are completely different. One is commonuse.Writer@78a2da20 and the other is commonuse.Writer@dd3b207. Also, while the name of the writer1 object has been changed to “Silent King ii,” the name of writer2 remains null.

From the results we can conclude that when Scope is prototype, each call to getBean() returns a new instance, and they are not the same object. Changing the state of either object does not change the other simultaneously.

3) Request, Session, Application, webSocket

These four scopes are only available in the context of a Web application and are not commonly used in practice. Request is used to create Bean instances for HTTP requests, session is used to create Bean instances for HTTP sessions, application is used to create Bean instances for ServletContext, Websocket is used to create Bean instances for a particular WebSocket session.

02, Bean field injection

“Brother, it is said that Spring development often involves calling various configuration files and requires the @value annotation. Can you give me more details?”

“No problem.”

1) Inject ordinary strings

Create a new ValueConfig class with the following contents:

@Configuration
public class ValueConfig {
    @Value("Silent King II.")
    private String name;

    public void output(a) { System.out.println(name); }}Copy the code

The @value annotation is used on the member variable name to indicate that the Value of the currently injected name is silent King two.

Create a new ValueMain class with the following contents:

public class ValueMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(SpELStringConfig.class); SpELStringConfig service = context.getBean(SpELStringConfig.class); service.output(); context.close(); }}Copy the code

The program output is as follows:

Silence reigned twoCopy the code

The result was in line with our expectations.

2) Inject Spring expressions

The easiest way to inject a regular string is with @Value. Let’s upgrade to inject a Spring expression and add first.

@Value(18 + "# {12}") / / 30
private int add;
Copy the code

Use #{} in double quotes. Let’s do some more relational and logical operations.

@Value(1 = = "# {1}") // true
private boolean equal;

@Value("# {400 > 300 | | 150 < 100}") // true
private boolean or;
Copy the code

If that’s not exciting enough, let’s do another triple operation.

@Value("# {2 > 1? 'Silence is golden' : 'No more silence '}") // "Silence is golden"
private String ternary;
Copy the code

3) Inject configuration files

If all this isn’t interesting enough, inject configuration files.

Create a new value.properties file in the Resources directory with the following contents:

Name = Age =18Copy the code

Create a new ValuePropertiesConfig class with the following contents:

@Configuration
@PropertySource("classpath:value.properties")
public class ValuePropertiesConfig {

    @Value("${name}")
    private String name;

    @Value("${age}")
    private int age;

    public void output(a) {
        System.out.println("Name:" + name + " 年纪:"+ age); }}Copy the code

The @propertysource annotation is used to specify which configuration file to load (value.properties), and classpath: indicates from the SRC or resources directory.

Note that @Value(“”) is marked with $instead of #, and {} is the key in the configuration file.

Create a new ValuePropertiesMain class with the following contents:

public class ValuePropertiesMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(ValuePropertiesConfig.class); ValuePropertiesConfig service = context.getBean(ValuePropertiesConfig.class); service.output(); context.close(); }}Copy the code

The running results of the program are as follows:

Name: ³ AA ¬ IoEy Age: 18Copy the code

“Alas, brother! Chinese garbled!”

“Don’t be afraid, third sister, the problem is easy to solve.”

First, look at how the Properties file is encoded.

If not UTF-8, change to UTF-8. At the same time, ensure that there are no Chinese garbled characters in the properties file after changing the encoding mode.

Then, add an encoding format to the @propertysource annotation.

@PropertySource(value = "classpath:value.properties",  encoding = "UTF-8")
Copy the code

After running the program again, the gibberish is blown away by the wind.

Name: Silent King Grade two: 18Copy the code

Initialization and destruction of beans

“Brother, it is said that in actual development, it is often necessary to add some extra operations in the Bean initialization and destruction, can you tell me how to implement it in detail?”

“No problem.”

1) the init method/destroy — method

Create a new InitDestroyService class with the following contents:

public class InitDestroyService {
    public InitDestroyService(a) {
        System.out.println("Construction method");
    }

    public void init(a) {
        System.out.println("Initialize");
    }

    public void destroy {
        System.out.println("Destroyed"); }}Copy the code

InitDestroyService() is the constructor, init() is the initialization method, and destroy() is the destruction method.

Create a new InitDestroyConfig class that looks like this:

@Configuration
public class InitDestroyConfig {
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public InitDestroyService initDestroyService(a) {
        return newInitDestroyService(); }}Copy the code

The @bean annotation initMethod specifies the method in which the Bean is initialized, and destroyMethod specifies the method in which the Bean is destroyed.

Create a new InitDestroyMain class that looks like this:

public class InitDestroyMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(InitDestroyConfig.class);
        InitDestroyService service = context.getBean(InitDestroyService.class);
        System.out.println("Prepare to close the container."); context.close(); }}Copy the code

The running results of the program are as follows:

The constructor initializes ready to close container destructionCopy the code

That is, the initialization method is executed after the constructor and the destruction method is executed after the container is closed.

2) @ PostConstruct / @ PreDestroy

Create a new InitDestroyService class with the following contents:

public class InitDestroyService {
    public InitDestroyService(a) {
        System.out.println("Construction method");
    }

    @PostConstruct
    public void init(a) {
        System.out.println("Initialize");
    }

    @PreDestroy
    public void destroy(a) {
        System.out.println("Destroyed"); }}Copy the code

The @postconstruct annotation serves the same purpose as the init-method annotation in the @bean annotation, specifying the method to execute after the Bean is initialized.

The @predestroy annotation does the same thing as the @bean annotation destroyMethod, specifying the method to execute after the Bean is destroyed by the container.

Create a new InitDestroyConfig class that looks like this:

@Configuration
public class InitDestroyConfig {
    @Bean
    public InitDestroyService initDestroyService(a) {
        return newInitDestroyService(); }}Copy the code

The @bean annotation no longer requires the init-method and destroyMethod arguments.

Create a new InitDestroyMain class that looks like this:

public class InitDestroyMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(InitDestroyConfig.class);
        InitDestroyService service = context.getBean(InitDestroyService.class);
        System.out.println("Prepare to close the container."); context.close(); }}Copy the code

The running results of the program are as follows:

The constructor initializes ready to close container destructionCopy the code

The result was in line with our expectations.

04. Configure a different environment for the Bean

“Brother, it is said that Spring development often needs to switch beans to different environments, such as development environment, test environment, formal production environment, can you tell me how to achieve this?”

“No problem.”

Consider a common scenario where we need to configure different data sources for development and formal production environments.

Create a Datasource class with the following contents:

public class Datasource {
    private String dburl;

    public Datasource(String dburl) {
        this.dburl = dburl;
    }

    // getter/setter
}
Copy the code

Dbname specifies the connection address of the database in different environments.

Create a new Config class with the following contents:

@Configuration
public class Config {
    @Bean
    @Profile("dev")
    public Datasource devDatasource(a) {
        return new Datasource("Development environment");
    }

    @Bean
    @Profile("prod")
    public Datasource prodDatasource(a) {
        return new Datasource("Formal production environment"); }}Copy the code

The @profile annotation is used to identify beans to be instantiated in different environments.

Create a new Main class with the following contents:

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        ConfigurableEnvironment environment = context.getEnvironment();
        environment.setActiveProfiles("prod"); context.register(Config.class); context.refresh(); Datasource datasource = context.getBean(Datasource.class); System.out.println(datasource.getDburl()); context.close(); }}Copy the code

When new AnnotationConfigApplicationContext objects do not specify a configuration class, Wait until the setActiveProfiles(“prod”) method is called to set the environment to a formal production environment before registering the configuration classes with the container through the register(config.class) method, and remember to refresh the container.

Run the program and output the following:

Formal production environmentCopy the code

Then change “prod” to “dev” and run the program again with the following output:

The development environmentCopy the code

“Brother, have you uploaded the sample code in this article to the code cloud? GitHub has been getting jammed recently.”

“That’s very sweet of you, third sister. Code cloud portal ~”

“Brother, you teach really good, I completely learned, not boring at all.”

“That must be, look forward to the next one?”

“Of course, looking forward to it, very much looking forward to it.”

Please allow me to make a warm joke, I don’t want to be sprayed on this article, for I have worked so hard to be original (creative + dry + fun), can you encourage me more? Stop it. Just like it. You’re the prettiest and the most handsome.

If you think this article is helpful to you, please search “Silent King ii” on wechat and read it for the first time. Reply [666] [1024] there are also 500G HIGH-DEFINITION teaching video prepared by me for you (classified), as well as a copy of the interview organized by the technical staff of DACHang.