该博客的普通读者知道我是Spring框架的大力支持者,但是我对应该使用它的方式持肯定的态度。 例如,我赞成显式对象实例化和显式组件连接,而不是自注释类,组件扫描和自动装配。
概念
尽管许多Spring开发人员都使用了这些概念,但是我的经验告诉我它们并不总是被完全理解。 一些解释是为了命令。
自注释类
自注释类是定义类如何通过Spring对类本身的注释进行实例化的类。 @Component
@Controller
, @Service
@Controller
, @Service
@Controller
和@Repository
是大多数Spring项目中常见的自注释类。
@Component
classMySelfAnnotatedClass{}
自注释类的主要缺点是类与Bean之间的硬耦合。 例如,不可能像显式创建那样实例化2个相同类的单例bean。 更糟糕的是,它将类也耦合到Spring框架本身。
注意, @Configuration
类也被认为是自注释的。
元件扫描
需要在上下文中列出和注册自注释类。 可以明确地做到这一点:
@Configuration
classMyConfig{
@Bean
funmyClass()=MySelfAnnotatedClass()
}
但是,最普遍的选择是让Spring框架在项目类路径上搜索每个自注释的类,然后根据注释对它们进行注册。
@Configuration@ComponentScan
classMyConfig
自动接线
一些bean需要依赖项才能被初始化。 将依赖项连接到依赖项bean可以是:
- 明确的:告诉哪个bean将满足依赖关系是开发人员的责任。
- 隐式(或自动):Spring框架负责提供依赖关系。 为此,单个Bean必须符合条件。
关于第二种选择,请重新阅读我的旧帖子以了解相关问题。
但是,有时无法避免自动装配。 当豆Bean1
在配置片段定义Config1
取决于豆Bean2
在片段定义Config2
,唯一可能的喷射选项自动装配。
@Configuration
classConfig2{
@Bean
funbean2()=Bean2()
}
@Configuration
classConfig1{
@Bean@Autowired
funbean1(bean2:Bean2)=Bean1(bean2)
}
在以上代码段中,使用了自动装配而不使用自注释类。
重新发明轮子
本周,我发现自己在旧版非Spring Boot应用程序中重新实现了Spring Boot的执行器。
该体系结构非常简单:HTTP端点返回通过Jackson库序列化的Java对象(或它们的列表)。 每个端点可能返回不同的对象,并且每个端点都可以使用自定义序列化程序进行序列化。
我已经按照每个端点打包的方式组织了该项目(与每层打包相反),并且已经提供了多个端点。 我希望人们为其他目标做出贡献,并且我希望它尽可能简单。 特别是,它们应仅:
- 声明控制器
- 声明配置类
- 实例化Jackson序列化器
其余的应该由我编写的通用代码来处理。
正确使用自动接线
通过使用位于项目主程序包中的主配置类上的@ComponentScan
,可以轻松处理控制器和配置类。 但是串行器呢?
Spring能够将注册到上下文中的特定类的所有bean收集到一个列表中。 这意味着每个程序包都将独立声明其序列化程序,并且通用代码可以处理注册:
@Configuration@EnableWebMvc@ComponentScan
classWebConfiguration:WebMvcConfigurerAdapter(){
@Autowired
privatelateinitvarserializers:List<StdSerializer<*>> (1)
overridefunconfigureMessageConverters(converters:MutableList<HttpMessageConverter<*>>){
converters.add(MappingJackson2HttpMessageConverter().apply{
objectMapper.registerModule(SimpleModule().apply{
serializers.forEach{addSerializer(it)}
})
})
}
}
- 魔术在这里发生。 该配置类已经编写完毕,新的程序包不需要做任何事情,序列化程序将成为列表的一部分。
这是一个这样的配置类的示例,声明一个序列化器bean:
@Configuration
classFooConfiguration{
@Bean
funfooSerializer()=FooSerializer()
}
classFooSerializer:StdSerializer<Foo>(Foo::class.java){
...
}
更好的是,如果需要将软件包进一步模块化为成熟的JAR,则此设置将以完全相同的方式工作,而无需进行任何更改。
结论
更好地了解自注释类,组件扫描和自动装配对所有Spring开发人员都是有益的。
而且,尽管它们在“标准” bean类中有很多缺点,但在配置类的范围内这样做不仅是完全可以接受的,而且甚至是一个优点。 在按功能逐包设计的项目中,它改善了模块化和去耦性。
翻译自: https://blog.frankel.ch/use-case-spring-component-scan/