Spring中,给静态变量初始化的问题

本文介绍了在Spring框架中如何通过不同方式使静态方法能够访问非静态成员变量,包括使用ServiceBeanFactory、@PostConstruct注解及ApplicationContextAware接口等方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方案一:推荐使用。
	
	/**
	 * 使用:ServiceBeanFactory.getUserService().getUserByName("jack");
	 */
        @Component
	public class ServiceBeanFactory {

		private static IUserService userService;

		@Autowired
		public void setUserService(IUserService userService) {
			 ServiceBeanFactory.userService = userService;
		}

		public static IUserService getUserService() {
			return userService;
		}
	}


方案二:使用@PostConstruct注解

	首先,声明一个静态变量staticTarget,静态变量staticTarget的类型要和非静态变量target的类型一致。
	然后,在带有@PostConstruct注解的方法中,将target的值赋给staticTarget。
	最后,在静态方法中通过调用静态变量staticTarget来实现对非静态变量target的调用。

	说明:
		1)在指定方法上加上@PostConstruct 注解来指定该方法是在bean初始化之后调用
		2)在指定方法上加上@PreDestroy 注解来指定该方法是在bean销毁之前调用
	
方案三:使用@PostConstruct注解

	首先,声明一个静态变量factory,这个静态变量factory的类型为该类自身。
	然后,在带有@PostConstruct注解的方法中,将this赋给这个静态变量factory,此时,factory指向了一个该类的实例(在容器启动的时候创建),故factory可以访问到该实例中的字段。
	最后,在静态方法中,通过调用静态变量factory来访问该类中的非静态变量。
	
	例子:
		@Component
		public class FailureTool {
			
		/*	// 方案一:
			@Autowired
			private MailUtil target1;
			
			@Autowired
			private ThreadPoolTaskExecutor target2;

			private static MailUtil staticTarget1;
			private static ThreadPoolTaskExecutor staticTarget2;
			
			@PostConstruct 
			public void init(){
				staticTarget1 = target1;
				staticTarget2 = target2;
			}*/
			
			
			// 方案二:
			@Autowired
			private MailUtil mailUtil;
			
			@Autowired
			private ThreadPoolTaskExecutor taskExecutor;
			
			private static FailureTool factory; 
			
			@PostConstruct 
			public void init(){
				factory = this;
			}
			
			public static void sendMail(AccountQuotaMonitor accountQuotaMonitor) {

			/*	// 方案一
				SendMailTask sendMailTask = new SendMailTask(staticTarget1, accountQuotaMonitor);
				FutureTask<Integer> futureTask = new FutureTask<Integer>(sendMailTask);
				staticTarget2.submit(futureTask);	*/
				
				// 方案二
				SendMailTask sendMailTask = new SendMailTask(factory.mailUtil, accountQuotaMonitor);
				FutureTask<Integer> futureTask = new FutureTask<Integer>(sendMailTask);
				factory.taskExecutor.submit(futureTask);
				
			}
		}
		

方案四:通过实现ApplicationContextAware接口来获取到Spring的ApplicationContext,进而可以获取到容器中的任何对象。

	说明:
		1)实现ApplicationContextAware接口的类,Spring在实例化该类时会自动调用setApplicationContext方法,
		2)在setApplicationContext方法中,将类型为ApplicationContext的入参的值赋值给该类的一个静态变量,
		3)然后就可以通过调用静态的getApplicationContext方法来获取到该类的静态变量,也即获取到了ApplicationContext。
		
	例子:
		
		@Component // 注:必须添加@Component注解,因为该类的实例化操作必须由Spring来完成。
		public class ApplicationContextUtil implements ApplicationContextAware {

			private static ApplicationContext context;

			@Override
			public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
				// TODO Auto-generated method stub
				ApplicationContextUtil.context = applicationContext;
			}

			public static ApplicationContext getApplicationContext() {
				return context;
			}
		}
		
		
		public class FailureTool {
			
			private static MailUtil mailUtil;
			private static ThreadPoolTaskExecutor taskExecutor;

			static {
				mailUtil = ApplicationContextUtil.getApplicationContext().getBean(MailUtil.class);
				taskExecutor = ApplicationContextUtil.getApplicationContext().getBean(ThreadPoolTaskExecutor.class);
			}
			
			public static void sendMail(AccountQuotaMonitor accountQuotaMonitor) {
				SendMailTask sendMailTask = new SendMailTask(mailUtil, accountQuotaMonitor);
				FutureTask<Integer> futureTask = new FutureTask<Integer>(sendMailTask);
				taskExecutor.submit(futureTask);
			}
		}


		
		
		

在 Java 中初始化 `static` 静态变量时,尤其是 `Map` 这样的复杂对象,需要特别注意初始化的时机和方式,以避免运行时异常,例如 `NullPointerException`。Java 提供了多种方式来初始化静态变量,包括直接初始化、静态代码块初始化以及使用 `@PostConstruct` 或依赖注入框架(如 Spring)的初始化方法。 ### 1. 直接初始化 可以直接在声明时初始化 `Map`,适用于简单的键值对集合: ```java public class Example { public static Map<String, String> myMap = new HashMap<>(); static { myMap.put("key1", "value1"); myMap.put("key2", "value2"); } } ``` ### 2. 使用静态代码块 静态代码块在类加载时执行一次,适用于需要执行更复杂逻辑的初始化: ```java public class Example { public static Map<String, String> myMap; static { myMap = new HashMap<>(); myMap.put("key1", "value1"); myMap.put("key2", "value2"); } } ``` ### 3. 使用 `@PostConstruct` 注解(适用于 Spring 管理的 Bean) 如果在 Spring 环境中使用,可以通过 `@PostConstruct` 注解在 Bean 初始化阶段进行更复杂的操作: ```java import javax.annotation.PostConstruct; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; @Component public class Example { public static Map<String, String> myMap; @PostConstruct public void init() { myMap = new HashMap<>(); myMap.put("key1", "value1"); myMap.put("key2", "value2"); } } ``` ### 4. 使用 `Supplier` 或 `Map.of`(Java 9+) 对于 Java 9 及以上版本,可以使用 `Map.of` 来简化初始化: ```java public class Example { public static Map<String, String> myMap = Map.of( "key1", "value1", "key2", "value2" ); } ``` 或者使用 `Supplier` 延迟初始化: ```java public class Example { public static final Map<String, String> myMap = new HashMap<>(Map.of( "key1", "value1", "key2", "value2" )); } ``` ### 注意事项 - 避免在 `static` 变量初始化过程中抛出异常[^2],尤其是在类加载阶段,否则会导致 `NoClassDefFoundError`。 - 使用 `@PostConstruct` 时需确保类被 Spring 管理,否则不会生效。 - 在多线程环境中,如果静态变量会被并发修改,应使用线程安全的 `Map` 实现,如 `ConcurrentHashMap`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值