最近,我被分配到一个项目,该项目禁用了一些自动配置,并主要使用KotlinDSL手动配置spring Boot 应用程序。
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
CassandraDataAutoConfiguration.class,
CassandraAutoConfiguration.class
})
我面临着我相信Kotlinlang与Spring集成的问题。
我来给你演示一下。
1.一个抽象的登录策略,其中包含@Transactional方法。
1.上述抽象类的具体子级。IndividualSignIn支持两种不同的实现。这些是谷歌和苹果的个人登录。差异的制造者是服务(Google登录服务,Apple登录服务),它被注入到上面的具体类bean中。我将在下面展示设置。
所以,Kotlindsl就像下面这样;
bean(name = "googleUserSignIn") {
IndividualUserSignIn(
ref("googleUserSignInService"),
ref("userHibernateDAO"),
ref("socialAccountHibernateDAO"),
ref("userService"),
...
)
}
bean(name = "appleUserSignIn") {
IndividualUserSignIn(
ref("appleUserSignInService"),
ref("userHibernateDAO"),
ref("socialAccountHibernateDAO"),
ref("userService"),
...
)
}
最后,代理请求的策略如下:
bean<UserSignInFactory>()
这些类的实现如下所示;首先是AbstractStrategy
abstract class AbstractUserSignIn(
private val userSignInService: UserSignInService,
private val userDAO: UserDAO,
private val socialAccountDAO: SocialAccountDAO,
private val userService: UserService,
....
) {
@Transactional
open fun signIn(userSignInRequest: SignInRequest): SignInResult {...}
fun getSignInStrategy(): UserSignInStrategy{ // **(A)**
return userSignInService.getSignInStrategy()
}
}
然后是从这个类继承的类;
open class IndividualUserSignIn constructor(
userSignInService: UserSignInService,
userDAO: UserDAO,
socialAccountDAO: SocialAccountDAO,
userService: UserService,
...
) : AbstractUserSignIn(
userSignInService,
userDAO,
socialAccountDAO,
userService,
...
) {
@PostConstruct
private fun init()
{
println("strategy :" + getSignInStrategy()) // **(B)**
}
...
}
工厂类。
@Component
open class UserSignInFactory @Autowired constructor(private val userSignInServices: Set<IndividualUserSignIn>) {
@PostConstruct
private fun createStrategies() {
userSignInServices.forEach { strategy ->
strategyMap[strategy.getSignInStrategy()] = strategy // **(C)**
}
}
....
companion object {
private val strategyMap: EnumMap<UserSignInStrategy, AbstractUserSignIn> = EnumMap(UserSignInStrategy::class.java)
}
}
(A)是问题产生的地方。抽象类使用注入的服务来让调用者了解其支持的实现。
问题就在这里
1.在点(B)处;在示例化具体策略时,@PostConstruct按预期工作并打印支持的策略。调试说this是策略的示例本身。
1.在点(C)处;在遍历Set时,我收到了一个NPE,因为在点(A)中使用的注入服务看起来为空。这里set中的元素是spring生成的代理的示例,指向上面步骤#1中的示例。
2条答案
按热度按时间u1ehiz5o1#
考虑将具体策略定义为lazy bean。
这将确保在工厂中访问策略之前,使用注入的正确依赖关系示例化策略。
更新为lazy beans:
然后更新UserSignInFactory类以适应惰性初始化:
mqxuamgl2#
这个问题似乎与Springbean的初始化顺序有关。特别是,在IndividualUserSignInService的bean完全初始化之前,UserSignInFactory bean就已经初始化了,这导致在调用getSignInStrategy()时,AbstractUserSignIn中的userSignInService字段为null。这可以使用KotlinDSL中bean方法的depends-on属性来完成:
是的,dependsOn属性确实不存在,我从一段似乎错误的代码中提取了这个示例,我使用了@DependsOn注解进行更正