让Spring Boot扫描不同的注解

huangapple go评论62阅读模式
英文:

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 {}

Documentation link


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!
...

huangapple
  • 本文由 发表于 2020年9月25日 20:37:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64064301.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定