Spring @Lookup 实现单例 bean 依赖注入原型 bean
一种解决的方法就是放弃依赖注入.你可以让 bean A 通过实现
ApplicationContextAware
接口并且在
bean A每次需要 bean B 的时候通过调用 getBean("B")向容器请求一个新的 bean B实例
另外一种方法是使用
@Lookup
注解
考虑一下这个场景:假如我们有大量的消息需要推送,为了提高性能,我们会使用一个任务池去实现,每个需要推送的消息就是一个任务.从这个业务场景中,我们至少可以提取几个 bean,一个是实现推送(阿里云移动推送,苹果 apns 等)的单例 bean,发送消息任务原型 bean,推送组件(任务池)单例 bean,还有一个是业务逻辑层的推送单例 bean(这个 bean 依赖推送组件 bean).我们用两种方法实现。
实现推送(阿里云移动推送,苹果 apns 等)的单例 bean
package com.simos.service;
import org.springframework.stereotype.Service;
/**
Created by l2h on 18-4-25.
Desc:模拟真正实现推送功能的底层类
@author l2h
*/
@Service
public class PushService {
public void pushMsg(String msg){
System.out.println(msg);
}
}
发送消息任务原型 bean
/**
Created by l2h on 18-4-25.
Desc: 推送消息任务
@author l2h
*/
@Service("task")
@Scope(SCOPE_PROTOTYPE)
public class PushMsgTask implements Runnable{
private String msg ;
public PushMsgTask(){
}
public PushMsgTask(String msg){
this.msg = msg;
}
@Autowired
PushService pushService;
@Override
public void run() {
pushService.pushMsg(msg);
}
public void setMsg(String msg){
this.msg = msg;
}
}
通过实现 ApplicationContextAware 接口单例 bean 中获取原型 bean
package com.simos.service;
import org.apache.tomcat.util.threads.TaskQueue;
import org.apache.tomcat.util.threads.TaskThreadFactory;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
Created by l2h on 18-4-25.
Desc:消息推送任务池组件.使用 aware,这样业务代码就依赖了 Spring 框架
@author l2h
*/
@Service
public class AwarePushMsgPool implements ApplicationContextAware{
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
线程池
*/
private ThreadPoolExecutor executorService;
/**
任务队列
*/
private TaskQueue taskqueue ;
/**
最大队列数量.通常配置在配置文件中.这里样例代码不加太多东西.
简单点使用 @value 注入,复杂点像 springboot 一样@Configuration+@ConfigurationProperties
*/
private final int acceptCount = 10000;
/**
*核心线程数
*/
private final int corePoolSize = 20;
/**
最大线程数
*/
private final int maxPoolSize = 100;
/**
线程保活时间
*/
private final int keepAliveTime =60;
public AwarePushMsgPool(){
taskqueue = new TaskQueue(acceptCount);
TaskThreadFactory tf = new TaskThreadFactory("simos-pool-msg-",true,Thread.NORM_PRIORITY);
executorService = new ThreadPoolExecutor(corePo
olSize,maxPoolSize,keepAliveTime, TimeUnit.SECONDS,
taskqueue, tf);
executorService.setThreadRenewalDelay(org.apache.tomcat.util.threads.Constants.DEFAULT_THREAD_RENEWAL_DELAY);
taskqueue.setParent(executorService);
}
public void pushMsg(String msg){
if (msg!=null){
try {
//所需要的原型 bean 不是通过依赖注入的,而是直接 bean 容器拿到的,违反了 IoC 原则
PushMsgTask task = pushMsgTask(msg);
task.setMsg(msg);
System.out.println("aware class:"+this.getClass());
executorService.submit(task);
}
catch (Exception exception){
System.out.println("推送失败,失败原因:"+exception.getMessage());
}
}
}
protected PushMsgTask pushMsgTask(String msg){
PushMsgTask task = applicationContext.getBean("task",PushMsgTask.class);
task.setMsg(msg);
return task;
}
}
通过实现 @Lookup 接口单例 bean 中获取原型 bean
package com.simos.service;
import org.apache.tomcat.util.threads.TaskQueue;
import org.apache.tomcat.util.threads.TaskThreadFactory;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
Created by l2h on 18-4-25.
Desc:消息推送任务池组件
@author l2h
*/
@Service
public class LookupPushMsgPool {
/**
线程池
*/
private ThreadPoolExecutor executorService;
/**
任务队列
*/
private TaskQueue taskqueue ;
/**
最大队列数量.通常配置在配置文件中.这里样例代码不加太多东西.
简单点使用 @value 注入,复杂点像 springboot 一样@Configuration+@ConfigurationProperties
*/
private final int acceptCount = 10000;
/**
评论