1.2.0 增加 IRepository IQuery的工厂方法,避免无用的空白接口编写

This commit is contained in:
2022-08-22 15:16:41 +08:00
parent 3c23c26a64
commit 53709b6fc3
9 changed files with 127 additions and 24 deletions

View File

@@ -17,7 +17,7 @@ buildscript {
subprojects { subprojects {
group 'com.synebula' group 'com.synebula'
version '1.1.2' version '1.2.0'
buildscript { buildscript {
repositories { repositories {

View File

@@ -2,16 +2,18 @@ package com.synebula.gaea.app.autoconfig.service
import com.synebula.gaea.data.serialization.IObjectMapper import com.synebula.gaea.data.serialization.IObjectMapper
import com.synebula.gaea.domain.repository.IRepository import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.domain.repository.IRepositoryFactory
import com.synebula.gaea.domain.service.Domain
import com.synebula.gaea.domain.service.IService import com.synebula.gaea.domain.service.IService
import com.synebula.gaea.domain.service.Service import com.synebula.gaea.domain.service.Service
import com.synebula.gaea.domain.service.ServiceDependency
import com.synebula.gaea.spring.autoconfig.Proxy import com.synebula.gaea.spring.autoconfig.Proxy
import org.springframework.beans.factory.BeanFactory import org.springframework.beans.factory.BeanFactory
import java.io.InvalidClassException import java.io.InvalidClassException
import java.lang.reflect.Method import java.lang.reflect.Method
class ServiceProxy( class ServiceProxy(
private var supertype: Class<*>, private var beanFactory: BeanFactory, implementBeanNames: Array<String> = arrayOf() private var supertype: Class<*>,
private var beanFactory: BeanFactory, implementBeanNames: Array<String> = arrayOf()
) : Proxy() { ) : Proxy() {
private var service: IService<*> private var service: IService<*>
@@ -20,18 +22,26 @@ class ServiceProxy(
// 如果没有实现类, 使用Service类代理 // 如果没有实现类, 使用Service类代理
if (implementBeanNames.isEmpty()) { if (implementBeanNames.isEmpty()) {
// 如果没有实现类并且没有ServiceDependency注解, 则抛出异常 // 如果没有实现类并且没有ServiceDependency注解, 则抛出异常
if (!this.supertype.declaredAnnotations.any { it.annotationClass == ServiceDependency::class }) { if (!this.supertype.declaredAnnotations.any { it.annotationClass == Domain::class }) {
throw InvalidClassException( throw InvalidClassException(
"interface ${this.supertype.name} must has implementation class or annotation by ${ServiceDependency::class.qualifiedName}" "interface ${this.supertype.name} must has implementation class or annotation by ${Domain::class.qualifiedName}"
) )
} }
val serviceDependency = this.supertype.getDeclaredAnnotation(ServiceDependency::class.java) val domain = this.supertype.getDeclaredAnnotation(Domain::class.java)
val repo = this.beanFactory.getBean(serviceDependency.repo.java)
// repository工厂对象
val defaultRepositoryFactory = this.beanFactory.getBean(IRepositoryFactory::class.java)
val mapper = this.beanFactory.getBean(IObjectMapper::class.java) val mapper = this.beanFactory.getBean(IObjectMapper::class.java)
val constructor = Service::class.java.getConstructor( val constructor = Service::class.java.getConstructor(
Class::class.java, IRepository::class.java, IObjectMapper::class.java Class::class.java, IRepository::class.java, IObjectMapper::class.java
) )
this.service = constructor.newInstance(serviceDependency.clazz.java, repo, mapper) this.service =
constructor.newInstance(
domain.clazz.java,
defaultRepositoryFactory.createRawRepository(domain.clazz.java),
mapper
)
} else { } else {
this.service = this.beanFactory.getBean(implementBeanNames[0]) as IService<*> this.service = this.beanFactory.getBean(implementBeanNames[0]) as IService<*>
} }

View File

@@ -51,4 +51,16 @@ class MongodbRepoRegister : Register() {
} }
return result return result
} }
private fun addDefaultProxyBean(result: MutableMap<String, BeanDefinition>) {
// IRepository proxy
val builder = BeanDefinitionBuilder.genericBeanDefinition(IRepository::class.java)
builder.addConstructorArgValue(IRepository::class.java)
builder.addConstructorArgValue(this._beanFactory)
builder.addConstructorArgValue(emptyArray<String>())
val definition = builder.rawBeanDefinition as GenericBeanDefinition
definition.beanClass = MongodbRepoFactory::class.java
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
result[IRepository::class.java.name] = definition
}
} }

View File

@@ -0,0 +1,23 @@
package com.synebula.gaea.mongodb.query
import com.synebula.gaea.query.IQuery
import com.synebula.gaea.query.IQueryFactory
import org.springframework.data.mongodb.core.MongoTemplate
class MongodbQueryFactory(var template: MongoTemplate) : IQueryFactory {
/**
* 创建IQuery接口类型
*/
override fun createRawQuery(clazz: Class<*>): IQuery<*, *> {
val constructor = MongodbQuery::class.java.getConstructor(Class::class.java, MongoTemplate::class.java)
return constructor.newInstance(clazz, this.template)
}
/**
* 创建IQuery接口类型
*/
override fun <T, I> createQuery(clazz: Class<T>): IQuery<T, I> {
return MongodbQuery(clazz, template)
}
}

View File

@@ -0,0 +1,24 @@
package com.synebula.gaea.mongodb.repository
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import com.synebula.gaea.domain.repository.IRepositoryFactory
import org.springframework.data.mongodb.core.MongoTemplate
class MongodbRepositoryFactory(var template: MongoTemplate) : IRepositoryFactory {
/**
* 创建IRepository接口类型
*/
override fun createRawRepository(clazz: Class<*>): IRepository<*, *> {
val constructor = MongodbRepository::class.java.getConstructor(Class::class.java, MongoTemplate::class.java)
return constructor.newInstance(clazz, this.template)
}
/**
* 创建IRepository接口类型
*/
override fun <T : IAggregateRoot<I>, I> createRepository(clazz: Class<T>): IRepository<T, I> {
return MongodbRepository(clazz, template)
}
}

View File

@@ -0,0 +1,19 @@
package com.synebula.gaea.domain.repository
import com.synebula.gaea.domain.model.IAggregateRoot
/**
* Repository 工厂接口。 定义了Repository的创建方法。
*/
interface IRepositoryFactory {
/**
* 创建原始类型的IRepository接口类型
*/
fun createRawRepository(clazz: Class<*>): IRepository<*, *>
/**
* 创建指定类型的IRepository接口类型
*/
fun <T : IAggregateRoot<I>, I> createRepository(clazz: Class<T>): IRepository<T, I>
}

View File

@@ -0,0 +1,13 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.domain.model.IAggregateRoot
import kotlin.reflect.KClass
/**
* 声明服务依赖的聚合根,若服务没有实现类则可以根据依赖项自动组装服务。
*
* @param clazz 依赖的聚合根类型
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Domain(val clazz: KClass<out IAggregateRoot<*>>)

View File

@@ -1,16 +0,0 @@
package com.synebula.gaea.domain.service
import com.synebula.gaea.domain.model.IAggregateRoot
import com.synebula.gaea.domain.repository.IRepository
import kotlin.reflect.KClass
/**
* 声明服务的依赖项,若服务没有实现类则可以根据依赖项自动组装服务。
*
* @param clazz 依赖的聚合根类型
* @param repo 依赖的[IRepository]类型
*/
annotation class ServiceDependency(
val clazz: KClass<out IAggregateRoot<*>>,
val repo: KClass<out IRepository<*, *>>,
)

View File

@@ -0,0 +1,18 @@
package com.synebula.gaea.query
/**
* Query 工厂接口。 定义了Query的创建方法。
*/
interface IQueryFactory {
/**
* 创建原始类型的IQuery接口类型
*/
fun createRawQuery(clazz: Class<*>): IQuery<*, *>
/**
* 创建指定类型的IQuery接口类型
*/
fun <T, I> createQuery(clazz: Class<T>): IQuery<T, I>
}