static final, static, @PostConstruct, constructor, @AutoWired execution order

static final, static, @PostConstruct, constructor, @AutoWired execution order

Scenes

When executing business, the general process is to call service to execute

That is, add the annotation @Service to a certain class and let it be managed by the spring container.

So in this service class, if there are variables or methods modified by static final / static / @PostConstruct, what is the execution order?

	private static final Integer AGE=12;

    static {
    
    
        System.out.println("static---static initializer"+AGE);
    }

    @PostConstruct //类初始化完成后,就执行这个方法
    private void init(){
    
    
        System.out.println("@PostConstruct--init"+AGE);
    }

As shown in the picture above
Then the order of execution when the project is started is (note here that my static variables are written above the static code block. In fact, whichever is written first is executed first. )

  1. Load static final first
  2. Then execute the static method
  3. Finally, execute @PostConstruct

If there is an inheritance relationship, then it is

1. Parent class static variables and static code blocks (those declared first are executed first);

2. Subclass static variables and static code blocks (those declared first are executed first);

3. Variables and code blocks of the parent class (those declared first are executed first);

4. The constructor of the parent class;

5. Variables and code blocks of subclasses (those declared first are executed first);

6. Constructor of subclass.

If constructors and automatic injection are added, the order is

  1. Static variables and static code blocks
  2. Construction method
  3. @AutoWired
  4. @PostConstruct

There are inheritance, static code blocks, construction code blocks, construction methods, @Autowired, @PostConstruct execution order

Execution order:

1. Parent class static variables and static code blocks (those declared first are executed first);
2. Subclass static variables and static code blocks (those declared first are executed first);
3. Variables and code blocks of the parent class (those declared first are executed first);
4. Construction methods of the parent class;
5. Variables and code blocks of subclasses (those declared first are executed first);
6. Construction methods of subclasses.
7. @Autowired
8. @PostConstruct

Static code block: executed only once when the class is loaded.

Construct a code block: create the object once and execute it once

The instance method of the class cannot be called in a static method, but the constructor method can be called (because an instance is not required).

class HelloA {
    
    
    static int staticParam = 1;
    int param = 0;

    static {
    
    
        System.out.println("static A");
        System.out.println("staticParam=" + staticParam);
    }

    {
    
    
        System.out.println("I'm A class");
        System.out.println("param=" + param);
    }

    public HelloA() {
    
    
        System.out.println("HelloA");
    }
}

public class HelloB extends HelloA {
    
    
    static {
    
    
        System.out.println("static B");
    }

    {
    
    
        System.out.println("I'm B class");
    }

    public HelloB() {
    
    
        System.out.println("HelloB");
    }
}
@Test
public void testStatic() {
    
    
	new HelloB();
}

Insert image description here

Detailed explanation of @PostConstruct annotation

Introduction
JavaEE5 introduces @PostConstruct and @PreDestroy two annotations that act on the Servlet life cycle to implement custom operations before Bean initialization and destruction

Usage scenarios
In the project, it is mainly to load some cache data before Servlet initialization

API Usage Instructions
The PostConstruct annotation is used on methods that need to be executed after dependency injection is completed to perform any initialization. This method must be called before placing the class into the service. All classes that support dependency injection must support this annotation. Methods annotated with PostConstruct must be called even if the class does not request any resources to be injected. Only one method can be annotated with this annotation. Methods applying the PostConstruct annotation must comply with all of the following criteria: The method must not have any parameters, except in the case of an EJB interceptor, according to Definition of the EJB specification, in which case it will take an InvocationContext object; the method's return type must be void; the method must not throw a checked exception; the method to which PostConstruct is applied can be public, protected, package private, or private ; Except for application clients, the method cannot be static; the method can be final; if the method throws an unchecked exception, the class must not be put into a service unless it is an EJB that can handle the exception and recover from it .

Features:
1. Only one non-static method can use this annotation

2. The annotated method must not have any parameters.

3. The return value of the annotated method must be void

4. The annotated method must not throw checked exceptions

5. This method will only be executed once

servlet execution process
img

Notes
Using this annotation will affect the service startup time. When the service starts, it will scan all files in WEB-INF/classes and all jar packages under WEB-INF/lib.

Usage of @PostConstruct annotation
@PostConstruct is an annotation introduced in java5. It refers to executing this method when the project is started. It can also be understood as starting the spring container. When executed, it can be used as a regular load of some data, such as a data dictionary.

The method modified by @PostConstruct will be run when the server loads Servle, and will only be executed once by the server. PostConstruct is executed after the constructor

That is, the loading order

The server loads the Servlet -> Loading of the servlet constructor -> postConstruct ->init (init is the initialization method in the service. An event that occurs when the service is created.) ->Service->destory->predestory- >Server uninstall serlvet

Then the question: the order of Constructor, @Autowired, @PostConstruct in spring
Constructor >> @Autowired >> @PostConstruct

As you can see from the literal meaning of dependency injection, if you want to inject object p into object a, you must first generate object p and object a before the injection can be performed. Therefore, if there is a member variable p in a class A that is annotated with @Autowired, then the @Autowired injection occurs after the constructor of A is executed.

@PostConstruct application scenario:
If you want to complete certain initialization operations when generating objects, but these initialization operations rely on dependency injection, then they cannot be implemented in the constructor. . To this end, you can use @PostConstruct to annotate a method to complete initialization. The @PostConstruct annotated method will be automatically called after dependency injection is completed.

@PostConstruct
    public void start() {
    
    
 
        try {
    
    
            int connect = producer.connect();
            if (connect == 0) {
    
    
                log.info("producer start success! groupName:{},namesrvAddr:{}", rocketMqProperties.getProducer().getGroupName(), rocketMqProperties.getNamesrvAddr());
 
            }
        } catch (MQException e) {
    
    
            e.printStackTrace();
        }
}
 
    @PreDestroy
    public void stop()  {
    
    
        try {
    
    
            if (producer != null) {
    
    
                producer.close();
                log.info("producer closed");
            }
        }catch (MQException a)
        {
    
    
            a.printStackTrace();
        }
}

In my recent work, I got a very practical annotation and would like to share it with you.
Pain Points
Children's shoes who have paid with WeChat or Alipay may have encountered this problem, which is to fill in the payment result callback, that is, after the payment is successful, Alipay needs Notify us according to the address we gave us, notifying us whether the user's payment is successful. If successful, we will process the corresponding business logic below. If we are testing the service, then we need to fill in the callback address for the test service. If it is published to Online, then we need to change it to an online address.

For the above scenario, we generally perform a dynamic configuration in the following way, without having to change it every time, to prevent problems.

public class PayTest {
    
    
 
    @Value("${spring.profiles.active}")
    private String environment;
 
    public Object notify(HttpServletRequest request) {
    
    
 
        if ("prod".equals(environment)) {
    
    
            // 正式环境
        } else if ("test".equals(environment)) {
    
    
 
            // 测试环境
        }
        return "SUCCESS";
    }
}

The above code seems to have no problem, but as brick movers, how can we move it like this? The posture is wrong!

Problem:
The scalability is too poor. If we need to use this parameter in other places, should we use the @Value annotation to obtain it again? If so Did our leader suddenly say that the word "test" seems too low? Change it to a higher-end one, replace it with "dev". Then do we need to change all the tests in the project? If there are fewer tests, it's better, but if there are more, it's better. Then we're afraid it won't be cold.

So can we make these configuration parameters into a global static variable, so that we can drink it directly? Even if we really want to change it then, I only need to change one thing.

Pay attention to big pitfalls
Some friends may be more confident, so why don’t I just add a static modification? If you really plan to do this, then be prepared Just pack up and leave. The value obtained by directly adding static is actually null. As for the reason, let's review the loading order of classes and static variables.

@PostConstruct annotation
Then since the problem has been stated, there must be a solution, otherwise you think I am playing with you.

First of all, this annotation is provided by Java, which is used to modify a non-static void method. It will run when the server loads the Servlet, and only runs once.

Transformation:

@Component
public class SystemConstant {
    
    
 
    public static String surroundings;
 
    @Value("${spring.profiles.active}")
    public String environment;
 
    @PostConstruct
    public void initialize() {
    
    
        System.out.println("初始化环境...");
        surroundings = this.environment;
    }
}

Result:
We can see that it was initialized when the project startedimg

At this point we can already get whether the current running environment is test or official, so that dynamic configuration can be achieved

img

Finally, I want to say
In fact, this annotation is far more useful than this. Like the Redis tool class I wrote before, I used RedisTemplate to operate Redis, so the method I wrote was useless. With static modification, every time you use the Redis tool class, you can only inject it into the container first and then call it. Using this annotation can perfectly solve this embarrassing problem. code show as below.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
 
import javax.annotation.PostConstruct;
 
/**
 * @ClassName RedisUtil
 * @Description TODO
 * @Version 1.0
 */
@Component
public class RedisUtil {
    
    
 
    private static RedisTemplate<Object, Object> redisTemplates;
 
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
 
    @PostConstruct
    public void initialize() {
    
    
        redisTemplates = this.redisTemplate;
    }
 
    /**
     * 添加元素
     *
     * @param key
     * @param value
     */
    public static void set(Object key, Object value) {
    
    
 
        if (key == null || value == null) {
    
    
            return;
        }
        redisTemplates.opsForValue().set(key, value);
    }
}


1. Introduction to @PostConstruct

Annotations provided by Java are used to modify methods. Methods modified by @PostConstruct will run when the server loads the Servlet, and will only be executed once by the server. PostConstruct is executed after the constructor and before the init() method.

(1)Conclusion:

The order of calls is: Constructor > @Autowired > @PostConstruct

(2)Function:

The method annotated with @PostConstruct is executed when the project is started. It can also be understood as being executed when the spring container is started. It can be used as a regular loading of some data, such as Read data dictionary, directory tree cache

2. Implementation method executed during bean initialization and destruction in Spring framework

Three ways to implement a method in the Spring framework when initializing and destroying beans.
(1) In the Spring framework, annotates @PostConastruct and @PreDestroy to implement Bean initialization execution and destruction execution methods. ;

(2) In the Spring framework, implements the interface InitializingBean and DisposableBean to implement the Bean initialization execution and destruction execution methods;

(3) In the Spring framework, pass the init-method="" of the bean in the xml configuration file destroy-method="" To implement the execution method when the Bean is initialized and destroyed;

Spring Bean execution order
Insert image description here

3. Project verification

1.MyServiceImpl

package com.huahua.myIdea.service.serviceImpl;

import com.huahua.myIdea.service.MyService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;

@Service
public class MyServiceImpl implements MyService, InitializingBean {
    
    

    @Override
    public int addTotal(int x, int y) {
    
    
        return 0;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        System.out.println("开始执行 afterPropertiesSet 方法: MyServiceImpl");
    }

    @PostConstruct
    public void postConstructMethod() {
    
    
        System.out.println("开始执行 PostConstruct 方法: MyServiceImpl");
    }

    @Autowired
    private void testAutowired(){
    
    
        System.out.println("开始执行 testAutowired 方法: MyServiceImpl");
    }

    MyServiceImpl(){
    
    
        System.out.println("开始执行 构造函数MyServiceImpl : MyServiceImpl");
    }
}

2.Test results

Insert image description here

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/135005253