前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring扩展点BeanPostProcessor

spring扩展点BeanPostProcessor

作者头像
叔牙
发布2020-11-19 15:08:35
5970
发布2020-11-19 15:08:35
举报
文章被收录于专栏:一个执拗的后端搬砖工

说起spring,想必每个开发人员都用过,spring是除了jdk之外java编程中最必不可少的基础框架,其优秀的编码方式和编程思想,值得每个技术人员学习和参考。spring给我们提供了很多扩展接口,方便我们开发过程中spring容器启动时或者启动结束做一些事情。此篇我们想要讲的是BeanPostProcessor接口的原理和使用方式。

源码分析

先看一下BeanPostProcessor接口的源码:

public interface BeanPostProcessor {

Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

BeanPostProcessor接口只有两个方法, postProcessBeforeInitialization和postProcessAfterInitialization:

1) postProcessBeforeInitialization方法:将此BeanPostProcessor应用于任何bean初始化回调,作用时机是InitializingBean的afterPropertiesSet方法或自定义init-method方法之前。bean已经被填充了属性值。返回的bean实例可以是围绕原件的包装器。

2) postProcessAfterInitialization方法:将此BeanPostProcessor应用于任何bean初始化回调,作用时机是InitializingBean的afterPropertiesSet方法或自定义init-method方法之后。bean已经被填充了属性值。返回的bean实例可以是围绕原件的包装器。

也就是说,实现了该接口的实例,可以在bean初始化之前和初始化之前做一些前置或者后置操作。

使用场景&编码实现

现在有很多优秀的持久层框架,但是有些公司或者项目架构比较轻量级一些,不想使用持久层框架,会选择自己封装一些DAO操作或者直接使用spring提供的jdbcTemplate操作数据库,在使用jdbcTemplate操作时为了避免每个DAO都写很多类似或者重复的sql操作,一般会抽象出一个通用的DAO操作类,例如BaseDao,里边会封装一些泛型的查询和更新操作,然后具体的调用和实现交给子类实现。

理论上,BaseDao层已经帮每个子类实现了大部分功能,子类只需要实现个性化逻辑,那么BaseDao就需要持有一个jdbcTemplate实例,这个jdbcTemplate实例要么是子类以方法调用的形式传进来,要么是BaseDao层持有,在容器启动的时候进行初始化。根据个人的使用经验来说,肯定是在容器启动的时候初始化,这样可以省去每次调用的时候重复性传参,并且非业务参数,接下来我们就使用代码实现:

BaseDao

public class BaseDao {

protected static final String select = "select ";

protected static final String from = " from ";

protected static final String where = " where ";

protected static final String and = " and ";

protected static final String orderBy = " order by ";

protected static final String oneEqOne = " 1=1 ";

protected static final String count = " count ";

protected static final String sum = " sum ";

protected static final String allSymbol = "(*) ";

protected static final String seqId = "seqId";

protected static final String star = " * ";

protected JdbcOperations jdbcTemplate;

protected JdbcOperations getJdbcTemplate() {

return jdbcTemplate;

}

public void setJdbcTemplate(JdbcOperations jdbcTemplate) {

this.jdbcTemplate = jdbcTemplate;

}

protected <T> T queryByPrimaryKey(String tableName, String primaryKey, Object value, Class<T> clazz) {

StringBuilder sqlBuilder = new StringBuilder();

sqlBuilder.append(select);

sqlBuilder.append(star);

sqlBuilder.append(from);

sqlBuilder.append(tableName);

if (null == primaryKey || 0 >= primaryKey.length()) {

primaryKey = "id";

}

sqlBuilder.append(where);

sqlBuilder.append(primaryKey);

sqlBuilder.append(" = ? limit 1 ");

log.debug("querySql-{}",sqlBuilder.toString());

return this.querySingleObj(clazz, sqlBuilder.toString(), new Object[]{value});

}

protected <T> T queryByPrimaryKey(String tableName, Object value, Class<T> clazz) {

return this.queryByPrimaryKey(tableName, null, value, clazz);

}

UserDao

@Repository("user2Dao")

public class User2Dao extends BaseDao {

private static final String TABLE_NAME = "User";

public User queryByPk(Long id) {

return this.queryByPrimaryKey(TABLE_NAME,id,User.class);

}

}

DataSourceConfig

/**

* 数据源配置类

*

*/

public class DataSourceConfig implements BeanPostProcessor {

@Autowired

private JdbcTemplate jdbcTemplate;

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

if(bean instanceof BaseDao) {

((BaseDao)bean).setJdbcTemplate(jdbcTemplate);

System.out.println(beanName + "完成设置jdbcTemplate");

}

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

return bean;

}

}

SpringBootConfig

@Configuration

public class SpringBootConfig {

@Bean

public DataSourceConfig dataSourceConfig() {

DataSourceConfig dataSourceConfig = new DataSourceConfig();

return dataSourceConfig;

}

}

最重要的就是DataSourceConfig这个类,DataSourceConfig实现了BeanPostProcessor接口,在实现postProcessBeforeInitialization中,判断bean是不是BaseDao的实例,如果是就把jdbcTemplate注入进去。作用就是在spring容器实例化了所有实现了BaseDao的子类之后,在调用初始化方法之前把jdbcTemplate填充进去,这样的话在调用每个子类Dao的时候jdbcTemplate都完成了初始化,就可以进行查询和更新操作了。

测试验证

针对上一步中的编码,我们首先启动springboot服务:

可以看到,在spring容器启动过程中给所有BaseDao的子类实例都填充了jdbcTemplate属性。既然容器启动没问题,接着我们编写测试代码测试一下Dao操作有没有问题:

UserManager

@Service("userManager")

public class UserManager {

@Autowired

private User2Dao user2Dao;

public User queryById(Long id) {

return this.user2Dao.queryByPk(id);

}

}

UserController

@RestController

public class UserController {

@Autowired

private UserManager userManager;

@RequestMapping("user/get/{id}")

public User queryUser(@PathVariable("id") Long id) {

User user = this.userManager.queryById(id);

return user;

}

}

再次启动应用,并从浏览器发起请求:

得到正常响应,说明我们之前的jdbcTemplate注入没有问题,可以像之前的实现方式一样访问DB。

总结

BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口。BeanPostProcessor的实现类注册到Spring IOC容器后,对于该Spring IOC容器所创建的每个bean实例在初始化方法(如afterPropertiesSet和任意已声明的init方法)调用前,将会调用BeanPostProcessor中的postProcessBeforeInitialization方法,而在bean实例初始化方法调用完成后,则会调用BeanPostProcessor中的postProcessAfterInitialization方法。

spring扩展接口中还有一个BeanFactoryPostProcessor与BeanPostProcessor比较类似,使用方式基本相似但是作用时机有所不同,实现BeanFactoryPostProcessor接口,可以在spring的bean创建之前,修改bean的定义属性,BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-09-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PersistentCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档