写点什么

Spring @Lookup 实现单例 bean 依赖注入原型 bean

作者:Java高工P7
  • 2021 年 11 月 11 日
  • 本文字数:2243 字

    阅读完需:约 7 分钟

  • 一种解决的方法就是放弃依赖注入.你可以让 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


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


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;


/**

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
Spring @Lookup实现单例bean依赖注入原型bean