大数跨境
0
0

基于Spring Boot实现不一样的通用DAO,值得学习

基于Spring Boot实现不一样的通用DAO,值得学习 Spring全家桶实战案例
2024-10-09
0
导读:基于Spring Boot实现不一样的通用DAO,值得学习

最新实战案例锦集:《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模块

@Servicepublic class UserService {    @PackAccess(User.class)  private GenericDao<User> userDao ;    public User save(User user) {    return this.userDao.persist(user) ;  }}

Product模块

@Servicepublic class ProductService {    @PackAccess(Product.class)  private GenericDao<Product> productDao ;    public List<Product> findAll() {    return this.productDao.findAll() ;  }}

这两个模块都声明了GenericDao对象,只是他们的具体泛型类型不同而已,这样定义后具体执行操作都是基于该Domain对象。

注意:注解中声明的Class对象要与泛型中的类型一致,否则将会抛出异常。这在后面的BeanPostProcessor中会看到。

2.4 自定义处理器

通用DAO及对应的模块Service都已经定义好了,接下来就是让Spring容器在创建这些Service对象时处理有@PackAccess注解的字段了。

@Componentpublic class DataAccessAnnotationProcessor implements BeanPostProcessor {
  private ConfigurableListableBeanFactory configurableBeanFactory; public DataAccessAnnotationProcessor(ConfigurableListableBeanFactory beanFactory) { this.configurableBeanFactory = beanFactory;  } @Override 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); }}

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832