导言
我们好,我是有清。
又快到了吃西瓜的季节,不知道我们有没有吃过无籽西瓜,西瓜从它的麦苗到成果需求通过很漫长的一段进程,在其麦苗的时分,咱们运用秋水仙素对其进行处理,然后再进行杂交,就能够得到无籽西瓜
那么,假如我想打破 Bean 传统的生命周期,在其创建到毁掉的进程中,去指定一些操作,有没有什么开箱即用的手段呢?学会这些对咱们的日常开发又有什么协助呢?接下来,让咱们一同学习一下
拓宽办法
运用 Spring 的接口
咱们能够完结 InitializingBean 接口,重写 afterPropertiesSet 办法,在这儿你就能够在 Bean 实例化之后自定义一些操作
代码示例
@Component
public class ImproveBeanTest1 implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("我进来了。。。");
}
}
既然在实例化之后有这样的接口,那么有没有相似的接口能够自定义咱们的毁掉 Bean 的时分做点拓宽?那当然有,便是 DisposableBean 接口
代码示例
@Component
public class ImproveBeanTest2 implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("糟糕。我被毁掉了");
}
}
或许一会儿你看了这两个示例,你会觉得这有个球用,可是格局打开,一旦咱们在结构级别上去考虑这个问题,咱们是不是能够凭借这个特性,进行一些预热操作、以及下线的时分进行高雅停机呢?
运用JSR-250注解
其实 JSR-250 的注解和上面供给的 Spring 的接口的功用很相似,别因为人家是 250 就瞧不起人家,它的效果一般便是使咱们的结构解耦与 Spring 结构,虽然咱们目前国内大部分用的都是 Spring 结构,不过,技多不压身,咱们来看一下
250 给咱们供给了了两个注解,分别是 @PostConstruct、@PreDestroy
有清老师小讲堂上线,Post 表明后置、Construct 表明结构,连起来便是后置结构的时分搞工作,便是在 Bean 初始化完结后对 Bean 进行处理
Pre 表明提早,Destroy 表明消毁,连起来便是前置毁掉的时分搞工作,便是在 Bean 毁掉阶段前做一些处理 代码示例
@Component
public class ImproveBeanTest3{
@PostConstruct
public void postConstruct() {
System.out.println("我是结构后置");
}
@PreDestroy
public void preDestroy() {
System.out.println("我是毁掉前置");
}
}
运用 @Bean 的特点
临时抽查:怎样使一个类交由 Spring 进行 Bean 办理,除了 @Component、@Controller、@Service、xml 装备,还有什么办法? 举手回答:“还能够运用 @Configuration 搭配 @Bean 注解”
对,此种办法也能够生成咱们的 Bean,当然也供给了“前置、后置”办法,show me code
@Configuration
public class ImproveBeanTest4 {
@Bean(initMethod = "onInitialize", destroyMethod = "onDestroy")
public ImproveBeanTest4 mySpringBean() {
return new ImproveBeanTest4();
}
public void onInitialize() {
System.out.println("我我我我进来");
}
public void onDestroy() {
System.out.println("我我我我出去了");
}
}
这边还有一点需求留意的是,假如咱们的 Bean 中含有 public 修饰的 close() 或许 shutdown() 办法,那么默许状况是会自动触发回调的,假如你不期望多此一举,你能够运用 destroyMethod=”” 去禁止这个行为
@Bean(destroyMethod = "")
public ImproveBeanTest2 mySpringBean2() {
return new ImproveBeanTest2();
}
public void close() {
System.out.println("我不能被执行了");
}
xml 装备文件中相同能够支撑这些骚操作,可是根据 xml 装备文件用的比较少,我就不展开说明了,感兴趣的小伙伴能够 官网走起:docs.spring.io/spring-fram…
运用 BeanPostProcessor
BeanPostProcessor 在整个 Bean 的周期应该是比较男一号的人物了,被用到的当地也很多,
在 Bean 初始化之前或之后,去自定义操作,乃至去狸猫换太子,怎样理解狸猫换太子,原本我准备生成 ABean,然后直接给他替换成 BBean,你或许会有疑问,这是什么骚操作,一会咱们的最佳实践会带你解开疑问,暂且先插个眼在这儿
咱们需求完结 BeanPostProcessor 接口,并且需求自动重写办法,上个代码,look 一下
@Configuration
public class ImproveBeanTest5 implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
这边咱们需求留意的是 BeanPostProcessor 的杀伤力十分广,对所有的 Bean 都会进行这个 processor 处理,所以一般咱们需求对 Bean 进行判别处理一下,不然我就想换一个太子,成果整个皇氏家族都被你换了
运用 Aware 接口
aware 接口,也能够拓宽 Bean 的生命周期,可是我这边以为一般咱们去完结 Aware 相关接口,最好去取东西而不是塞东西,为什么这么说?
咱们来翻译一下 aware 的意思,这个英文的意思是可感知、察觉的,假如 bean 完结了一些 aware 办法,能够说是上级办法调用到咱们这儿来,把变量传递给了咱们,这个时分咱们尽或许去取东西,而不是写,想写操作或许更改特点,主张运用 BeanPostProcessors
就好比咱们事务开发的时分,他人调用咱们 的办法,给了咱们一个 model 目标,咱们去取其间一两个特点,完结咱们的事务逻辑,有必要的话,再分装一个新的 model 回去,假如咱们把这个 model 目标改了,一旦出问题了,就很有或许被 diss 说,你为啥改了我给你的目标,日志打的都不对了, 这问题都没法排查了
当然运用 aware 去写当然没问题哈,只是一个编程习气的问题,来上代码
@Component
public class ImproveBeanTest6 implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println("-------" + name);
}
}
Spring 给咱们供给了十分多的 Aware接口,能够按需运用:docs.spring.io/spring-fram…
最佳实践
凭借 InitializingBean 完结工厂形式
咱们知道工厂形式,其实在咱们日常的开发进程中出镜率还是比较高的,那么咱们怎样运用 InitializingBean 这个接口,去高雅完结咱们的工厂形式呢
咱们这边举一个,咱们知道咱们房贷能够正常还款,和排个半年的队提早还款,或许刺激的逾期不还,咱们就凭借这样的一个小 case,去展开一下咱们的代码
闲话少说,直接看代码
@Component
public class CommonRepayFactory {
private static final Map<String, IRepayFactory> REPAY_FACTORY_MAP = new ConcurrentHashMap<>();
public static IRepayFactory getRepayFactory(String type) throws Exception {
IRepayFactory repayFactory = REPAY_FACTORY_MAP.get(type);
if (Objects.isNull(repayFactory)) {
throw new Exception("搞的啥,没有这个工厂");
}
return repayFactory;
}
public static void register(String factoryType, IRepayFactory repayFactory) {
REPAY_FACTORY_MAP.put(factoryType, repayFactory);
}
}
// 提早还款工厂
@Component
@Slf4j
public class AdvanceRepayFactory implements IRepayFactory, InitializingBean {
@Override
public void repay(RepayRequest request) {
// 还款操作
}
@Override
public void afterPropertiesSet() {
CommonRepayFactory.register("提早还款", this);
}
}
// 调用途直接 CommonRepayFactory.getRepayFactory(request.getRepayBizType()).repay(request)
这一个工厂形式你改吧改吧,就能直接搬到你的项目中运用了,不用谢,我叫雷锋,具体代码地址见文章尾部
凭借 ApplicationContextAware 获取所需的 Bean
咱们在实际开发的进程中或许会碰到这样的问题,我在某个东西类的静态办法中想注入了某个 Bean,可是不能直接 @Autworied 这个 Bean,这个时分咱们有取巧注入的办法,可是当你这个 Bean 是 jar 包引入的并且是多态的你能够直接 @Autworied 么?所以咱们一般需求一个东西类去获取 Bean
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
private ApplicationContextUtils() { }
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
public static <T> T getBeanByType(Class<T> clazz) throws Exception {
if (applicationContext == null) {
throw new Exception("搞什么,瞎拿");
}
return applicationContext.getBean(clazz);
}
public static <T> T getBeanByName(String beanName) throws Exception {
if (applicationContext == null) {
throw new Exception("搞什么,瞎拿");
}
return (T) applicationContext.getBean(beanName);
}
}
凭借 BeanPostProcessor 完结狸猫换太子
先看个代码示例,应该是比较简单易懂的
@Component
public class ImproveBeanTest7 implements ApplicationContextAware, BeanPostProcessor {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("defaultConfig")) {
// 假如遇到需求替换的Bean,咱们直接换成自己完结的Bean即可(这儿能够把就得removeBeanDefinition,然后注册新的registerBeanDefinition)
// 这儿的myConfig要继承自defaultConfig,不然引证的当地会报错 return applicationContext.getBean("myConfig");
}
return bean;
}
}
这时分或许会有同学有疑问了,假如我有多个完结了 BeanPostProcessor 的接口这么办,其实这个问题,代码里给了咱们答案,咱们会进行循环处理,一旦 postProcessBeforeInitialization 返回值不为空,咱们就直接取当时的返回值了,不再进行循环处理
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
总结
通过上面的讲解,其实咱们知道了怎样对 Bean 进行拓宽,以及了解了部分的完结场景,或许还收成了两个小轮子,可是或许现在你暂时还用不上,你只需收藏,其余的交给收藏夹处理
当然假如这篇文章真的对你有所协助,期望你点赞分享,你的支撑是我写作最大的动力,有什么问题都欢迎私信进行沟通交流
文章中的代码地址:github.com/isysc1/Issu…
闲言碎语
上周二,是情人节,我们都在讨论关于爱的出题,而我在公司苦苦加班考虑这行代码怎样写
后来下班了,路上人山人海,有出售爱情的商贩、有对浪漫过敏的城管、有相拥而笑的恋人、还有拉着行李箱仓促而过的他和她,好像我们都在为这个出题写上自己以为的答案
而这时,突然间一个小女子跑过来对我说:“哥哥,你要买花吗?”
我问她:“你的花呢”?
小女子说:“人要先感到幸福,才能看到玫瑰。”