最新实战案例锦集:《Spring Boot实战案例合集》持续更新,每天至少更新一篇文章,订阅后将赠送文章最后展示的所有MD文档(学习笔记)。
环境:Spring Boot3.2.5
1. 简介
本篇文章,将使用 Bean 后处理器(BeanPostProcessor)自动生成DAO对象,然后通过自定义注解注入对应生成的DAO对象。这可以重复使用同一个 Bean,而不必创建多个相同类型的类似 Bean对象。
简单说就是,我们在项目中不用再为每一个模块定义DAO对象了,而是通过一个通用的DAO对象(如:GenericDAO<Entity>)来表示所有模块的DAO,而这里的泛型指定了是哪个模块对象。
接下来,我将详细的介绍每一个核心类的编写及作用。
2. 实战案例
2.1 通用DAO
首先,我们需要定义一个通用的DAO对象,该对象中定义了通用的CRUD方法。
public class GenericDao<E> {private final Class<E> entityClass;public GenericDao(Class<E> entityClass) {this.entityClass = entityClass;}public List<E> findAll() {System.err.println(this.entityClass + ", finaAll") ;return null;}public E persist(E entity) {System.err.println(this.entityClass + ", persist") ;return entity ;}}
具体的代码实现,你可以根据你当前使用JPA/MyBatis来实现。如:你使用的JPA,那么你可以在GenericDAO中直接注入EntityManager对象。
2.2 自定义注解
自定义注解会应用到具体每个业务模块中的字段上(如:Service中注入DAO对象),被注解标注的字段会被BeanPostProcessor处理器处理。
@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })@Documentedpublic @interface PackAccess {Class<?> value() ;}
只有一个属性value,必填;用来指定当前是哪个Domain对象。
2.3 注入GenericDAO对象
接下来,就是如何在我们的Service中使用DAO对象了,我这里为了演示定义了2个模块User和Product。
User模块
public class UserService {private GenericDao<User> userDao ;public User save(User user) {return this.userDao.persist(user) ;}}
Product模块
public class ProductService {private GenericDao<Product> productDao ;public List<Product> findAll() {return this.productDao.findAll() ;}}
这两个模块都声明了GenericDao对象,只是他们的具体泛型类型不同而已,这样定义后具体执行操作都是基于该Domain对象。
注意:注解中声明的Class对象要与泛型中的类型一致,否则将会抛出异常。这在后面的BeanPostProcessor中会看到。
2.4 自定义处理器
通用DAO及对应的模块Service都已经定义好了,接下来就是让Spring容器在创建这些Service对象时处理有@PackAccess注解的字段了。
public class DataAccessAnnotationProcessor implements BeanPostProcessor {private ConfigurableListableBeanFactory configurableBeanFactory;public DataAccessAnnotationProcessor(ConfigurableListableBeanFactory beanFactory) {this.configurableBeanFactory = beanFactory;}public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {this.configureFieldInjection(bean) ;return bean;}private void configureFieldInjection(Object bean) {Class<?> managedBeanClass = bean.getClass();FieldCallback fieldCallback = new PackAccessFieldCallback(configurableBeanFactory, bean);// 处理字段ReflectionUtils.doWithFields(managedBeanClass, fieldCallback);}}

