英文:
Make Spring Boot Scan for different Annotations
问题
为了充分发挥春季魔法的威力,请使用 @Component
或任何派生的注解来注解您的 活动 组件,在春季自动将您的应用程序连接在一起。
到目前为止还不错。
现在,我想根据Clean Architecture/Hexagonal Architecture模式来构建我的应用程序,并希望将Spring与我的内部圈子(领域)分离开来。为了实现这一点,我可以简单地放弃春季的魔法,创建一些带有一些 @Bean
提供方法的 @Configuration
类。
也就是说,创建大量的样板代码并且需要足够的领域知识来配置一切 - 这不是我想要的。
我想要的是:我想要用诸如 @UseCase
、@Port
、@Service
、@Entity
、@EntityId
、@ValueObject
和其他有意义的注解来注解我的领域类型,携带有关这些类的领域知识和意图 - 并且在外层尽量多地使用春季的魔法,以自动化配置,根据领域层中声明的必要知识。
我可以通过在 @UseCase
注解中隐藏一个 @Component
注解来做到这一点,但这样我的领域部分仍然会依赖于Spring - 只是多了一些间接性。
我更希望的是,告诉Spring不要寻找 @Component
,而是寻找 @UseCase
。我的想象告诉我,Spring的工作方式大致如下:
for (class in classpath-with-matching-package) {
if (class has annotation '@Component') {
createBeanDefinitionForClass(class)
}
}
createBeansForDefinitions()
我希望能够通过配置或扩展告诉执行检查的方法,它是否具有 @Component
注解,以检查它是否具有其他有意义的注解。
然而,我不知道哪个类和/或方法可能负责这个任务。
简要的问题:
- 哪个类(们)负责查找我的带有 @Component 注解的类?
- (如何)我可以影响它们查找带有 @UseCase 注解的类,其中 @UseCase 不包含 @Component?
您也可以随意尊重地评论一下,为什么我的想法很愚蠢。那总是最具启发性的!
英文:
To utilize the full power of spring magic, annotate your active components with @Component
or any derived annotation, lean back and relax while Spring wires together your application.
Sofar so good.
Now I want to structure my app according to the Clean Architecture/Hexagonal Architecture pattern, and desire to keep Spring away from my inner circle, the domain. To achive that, I could simply drop the spring magic and create a couple of @Configuration
-classes with some @Bean
-providing methods.
That is, creating a lot of boilerplate code and the necessity of having enough domain knowledge to configure everything - so not, what I want.
What I want: I want to annotate my domain types with annotations like @UseCase
, @Port
, @Service
, @Entity
, @EntityId
, @ValueObject
and other meaningfull annotations, carrying the domain knowledge and intent regarding those classes - and use as much spring magic as possible in the outer layer, to automate the configuration, drawing necessary knowledge as declared in the domain layer.
I could do that, hiding the Spring Dependency by hiding an @Component
-Annotation within the @UseCase
-Annotation, but then I my domain part would still be spring dependent - just with some indirection.
What I would prefer is, telling Spring to not look for @Component
but for @UseCase
instead. My imagination tells me, Spring works somehow like this:
for (class in classpath-with-matching-package) {
if (class has annotation '@Component') {
createBeanDefinitionForClass(class)
}
}
createBeansForDefinitions()
And I hope, it is possible to tell the method which does the check, whether the class has the @Component
-Annotation to check wether it has some other, meaningful annotation, either by configuration or by extension.
However, I have no clue, what class and or method might be responsible for this task.
Questions in short:
- Which class(es) are responsible for finding my @Component-annotated classes?
- (How) can I influence them to find @UseCase-annotated classes, where @UseCase does not include @Component?
Also feel free, to respectfully comment, why my idea is stupid. Thats always the most enlightening!
This is in Response to the answer by @Ghokun which seems reasonable but fails
My Example-Project has the following structure:
src/main/java/de/mycorp/group
|-> /exampleapp
|-> NoComponentDemoApp.java
|-> UseCaseScan.java
|-> /springless
|-> SomeUseCase.java
|-> UseCase.java
NoComponentDemoApp.java:
@SpringBootApplication
public class NoComponentDemoApp
{
public static void main(String[] args)
{
SpringApplication.run(NoComponentDemoApp.class, args);
}
}
UseCaseScane.java
@Configuration
@ComponentScan(
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(UseCase.class)}, // type default/annotation, value synonym of classes
basePackages = "de.mycorp.group.springless"
)
public class UseCaseScan
{
}
SomeUseCase.java
@UseCase
public class SomeUseCase
{
private static final Logger logger = LoggerFactory.getLogger(SomeUseCase.class);
public SomeUseCase()
{
logger.info("Some Actor created");
}
}
UseCase.java
public @interface UseCase
{
}
Ofc. when I enable default filters and mark SomeUseCase.java
with @Component
it works. But something fails. For brevity I removed import. Package info can be deduced from the structure. If deemed necessary, I will add it.
答案1
得分: 1
Spring已经为您提供了以下配置选项:
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
@ComponentScan(useDefaultFilters = false,
includeFilters = {@Filter(type = FilterType.ANNOTATION, class= UseCase.class)})
public class AppConfig {}
编辑:
使用以下配置可以运行。请检查您的类:
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
@SpringBootApplication
@ComponentScan(useDefaultFilters = false, includeFilters = { @Filter(UseCase.class) })
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
package demo;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@UseCase
public class AnnotatedClass {
private static final Logger logger = LoggerFactory.getLogger(AnnotatedClass.class);
@PostConstruct
public void init() {
logger.info("It Works!");
}
}
package demo;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Indexed;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface UseCase {
}
...
2020-09-28 03:25:02.913 INFO 6829 --- [ main] demo.AnnotatedClass: It Works!
...
英文:
Spring already gives you that option with the following configuration:
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
@ComponentScan(useDefaultFilters = false,
includeFilters = {@Filter(type = FilterType.ANNOTATION, class= UseCase.class)})
public class AppConfig {}
Edit:
It works with following configuration. Please check your classes:
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
@SpringBootApplication
@ComponentScan(useDefaultFilters = false, includeFilters = { @Filter(UseCase.class) })
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
package demo;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@UseCase
public class AnnotatedClass {
private static final Logger logger = LoggerFactory.getLogger(AnnotatedClass.class);
@PostConstruct
public void init() {
logger.info("It Works!");
}
}
package demo;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Indexed;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface UseCase {
}
...
2020-09-28 03:25:02.913 INFO 6829 --- [ main] demo.AnnotatedClass: It Works!
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论