@NoRepositoryBean:Spring Data Jpa在啟動時就不會去實例化BaseRepository這個接口
1.通用接口:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.NoRepositoryBean; /** * 通用DAO接口 * */ @NoRepositoryBean public interface DAOInterface<T> extends JpaRepository<T, Long>, JpaSpecificationExecutor<T> { }
2.添加自定義方法:
2.1自定義Repository接口
@NoRepositoryBean public interface BaseRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> { boolean support(String modelType); }
- 添加
BaseRepository接口 BaseRepository繼承了PagingAndSortingRepository,這樣可以保證所有Repository都有基本的增刪改查以及分頁等方法。- 在
BaseRepository上添加@NoRepositoryBean標注,這樣Spring Data Jpa在啟動時就不會去實例化BaseRepository這個接口 - 添加
support(String modelType)方法,表示該Repository的領域對象是否為modelType類型
2.2實現BaseRepository接口
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> { private final Class<T> domainClass; public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) { super(domainClass, entityManager); this.domainClass = domainClass; } @Override public boolean support(String modelType) { return domainClass.getName().equals(modelType); } }
定義好自定義的方法后,我們現在通過一個基本的Repository類來實現該方法:
首先添加BaseRepositoryImpl類,繼承SimpleJpaRepository類,使其擁有Jpa Repository的基本方法。
我們發現Repository有兩個構造函數:
- SimpleJpaRepository(JpaEntityInformation entityInformation, EntityManager entityManager)
- SimpleJpaRepository(Class domainClass, EntityManager em)
這里我們實現第二個構造函數,拿到domainClass和EntityManager兩個對象。因為我們要實現的是知道某個Repository是否支持某個領域對象的類型,因此在實現構造函數時我們將domainClass的信息保留下來。
最后實現support方法,其參數是領域對象的類型,將其和domainClass對比,如果相等,則該Repository支持該類型的領域對象:
2.3創建自定義RepositoryFactoryBean
接下來我們來創建一個自定義的RepositoryFactoryBean來代替默認的RepositoryFactoryBean。RepositoryFactoryBean負責返回一個RepositoryFactory,Spring Data Jpa 將使用RepositoryFactory來創建Repository具體實現,這里我們用BaseRepositoryImpl代替SimpleJpaRepository作為Repository接口的實現。這樣我們就能夠達到為所有Repository添加自定義方法的目的。
public class BaseRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> { @Override protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) { return new MyRepositoryFactory(em); } private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory { private final EntityManager em; public MyRepositoryFactory(EntityManager em) { super(em); this.em = em; } @Override protected Object getTargetRepository(RepositoryMetadata metadata) { return new BaseRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), em); } @Override protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { return BaseRepositoryImpl.class; } } }
2.4配置Jpa factory class
最后,我們需要配置Jpa使用我們自定義的BaseRepositoryFactoryBean。Spring支持使用標注進行配置,我們在com.tmy.App中添加標注@EnableJpaRepositories(repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class):
@SpringBootApplication @EnableJpaRepositories(repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class) public class App { public static void main( String[] args ){ SpringApplication.run(App.class, args); } }
這樣我們就為所有Repository添加了自定義的方法。
2.5測試
我們添加了一個TestController進行測試。進入根目錄,執行mvn spring-boot:run可以運行我們的應用。
應用啟動后,分別訪問http://localhost:8080/test?type=blog&id=1和http://localhost:8080/test?type=article&id=1,我們將看到article和blog兩個不同的對象。
在TestController中,我們通過依賴式注入獲取到所有Repository的列表。當用戶訪問/test,系統將根據傳進來的type遍歷所有Repository,找到對應的Repository,再調用findOne(id)方法找到對應的對象。這樣我們就不需要一個一個的去獲取Repository實例,當領域對象越來越多時,通過這種方式是一種更加高效的對象管理方法。
@RestController public class TestController { @Autowired private List<BaseRepository> repositories; @RequestMapping(value = "/test", method=RequestMethod.GET) public Object getEntry(@RequestParam(value="type", required = true) String type, @RequestParam(value="id", required=true) Integer id){ if(type.equals("article")){ type = Article.class.getName(); }else if (type.equals("blog")) { type = Blog.class.getName(); } for (BaseRepository baseRepository : repositories) { if(baseRepository.support(type)){ return baseRepository.findOne(id); } } return null; } }
參考:
https://www.tianmaying.com/tutorial/spring-jpa-custom-all
