Thoughts on Using JavaBean in Java Static Method

written in front

First of all, the Java language does not support the use of non-static methods in static methods. The main reason is that static methods are stateless, and non-static methods will cause NonPointException (this problem will fail at compile time); the Java language will directly restrict such use.
But many times when we maintain old code, due to some limitations of the framework, we have to find a way to break through this limitation. At this time, we usually use a compromise method, defining a static referenced class in the class, and then annotating @PostConstructa initmethod , assign the referenced class to an automatically injected instance in the method, and then use the defined static referenced class in the static method. The method is as follows: Call the method of the object injected by @Autowired in the static method.
I found that this method can indeed be used in actual use, but it is limited, that is, it can be obtained when the instance of the class calls this static method, but when this When the class is a tool class, that is, when we usually use the class name to directly call the static method, this method cannot work. In any case, the reference class you inject is null, so there is no way. Then you can only introduce the reference class used inside the static method.
We can use the getBean method of Spring ApplicationContext to obtain an instance of the reference class.
In a word, the static method can be called as an instance method after the previous method is processed, and the static method can be called as a class method after the latter method is processed.

Invoke methods of @Autowired injected objects in static methods

There are many examples on the Internet here, I will pick one at random.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;

@Service // 这里必须要有spring bean的注解,没有可以添加@component
public class DataTraceServiceImpl {
    
    

    @Autowired
    private DataTraceRepository dataTraceRepository; //自动注入引用类
    private static DataTraceRepository dataTraceRepositoryStatic; // 创建静态引用类

    @PostConstruct
    public void init() {
    
    
    	// 构造完成之后将自动注入的引用类实例赋值给静态应用类
        dataTraceRepositoryStatic = this.dataTraceRepository;
    }

    /**
     * 根据实体id查询实体的数据追溯
     * @param entityId 实体Id
     */
    public static List<DataTrace> count(Integer entityId) {
    
    
        // 这里就这么调用
        return dataTraceRepositoryStatic.findAllByEntityId(entityId);
    }

}

This method can be used because both the application class and the referenced class are in the spring bean container, and the application class is also called by the instance used when calling the static method. However, when calling with a class name plus a static method, this method will not work.

Introduce the JavaBean object inside the static method

General ways to introduce JavaBean objects (three)

  1. Autowired automatic injection method
  2. Ways of Constructor Injection
  3. Ways to get beans using ApplicationContext

The first two methods are obtained at the class level, and the latter method can be called in a method.

Ways to get the ApplicationContext object

To obtain a Bean, you must first obtain the ApplicationContext object. There are also three ways to obtain it: (a bit imprecise, but anyway this is not the focus of our attention)

  1. Autowired automatic injection method
  2. Ways of Constructor Injection
  3. Implement the interface ApplicationContextAware provided by spring

If the first two are still unavailable, then the third method will be used

import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

@Component
public class SpringContextHolder implements ApplicationContextAware {
    
    

    private ApplicationContext applicationContext;

    public void show (){
    
    
        System.out.println(applicationContext.getClass());
    }

	/**
	*    spring 在bean 初始化后会判断是不是ApplicationContextAware的子类,调用setApplicationContext()方法, 会将容器中ApplicationContext传入进去
	*/
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        this.applicationContext = applicationContext;
    }
	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
    
    
		assertContextInjected();
		return (T) applicationContext.getBean(name);
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	public static <T> T getBean(Class<T> requiredType) {
    
    
		assertContextInjected();
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 检查ApplicationContext不为空.
	 */
	private static void assertContextInjected() {
    
    
		Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
	}
}

Use ApplicationContext to get class in Static method

import java.util.List;

public class DataTraceServiceImpl {
    
    
    /**
     * 根据实体id查询实体的数据追溯
     * @param entityId 实体Id
     */
    public static List<DataTrace> count(Integer entityId) {
    
    
    	DataTraceRepository service = SpringContextHolder.getBean(DataTraceRepository.class);
        
        return service.findAllByEntityId(entityId);
    }

}

Reference article: Three ways to get ApplicationContext in SpringBoot
by calling @Autowired injected object method in static method

Guess you like

Origin blog.csdn.net/zhoulizhu/article/details/119031772