1. 程式人生 > >spring boot去除掃描自動注入依賴方法——Spring常用註解使用方法

spring boot去除掃描自動注入依賴方法——Spring常用註解使用方法

問題:
最近做專案的時候,需要引入其他的jar。然後還需要掃描這些jar裡的某些bean。於
是使用註解:@ComponentScan
這個註解直接指定包名就可以,它會去掃描這個包下所有的class,然後判斷是否解析:

原始碼:

public @interface SpringBootApplication {
    @AliasFor(
        annotation = EnableAutoConfiguration.class,
        attribute = "exclude"
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class,
        attribute = "excludeName"
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}


public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default "**/*.class";

    boolean useDefaultFilters() default true;

    ComponentScan.Filter[] includeFilters() default {};

    ComponentScan.Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}
@ComponentScan(basePackages = {"your.pkg", "other.pkg"})

public class Application {

} 

其他的jar中定義了 redissonConfig 這個bean。然後我自己的專案也定義了redissonConfig 這個bean。導致專案啟動報錯。所以使用如下方式,排除jar 中的RedissonConfig.class。

@ComponentScan(basePackages = {"com.xx.xx.*"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {RedissonConfig.class}))

或者

 

@SpringBootApplication(scanBasePackages = {
    "org.activiti.rest",
    "org.activiti.app.conf",
    "org.activiti.app.repository",
    "org.activiti.app.service",
    "org.activiti.app.security",
    "org.activiti.app.model.component",
    "org.activiti.engine"},
    exclude = {
        //org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class,
        //org.activiti.spring.boot.SecurityAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class,
        JpaRepositoriesAutoConfiguration.class, //禁止springboot自動載入持久化bean
        org.activiti.spring.boot.JpaProcessEngineAutoConfiguration.class})
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {
    DatabaseConfiguration.class}))

 @ComponentScan註解。掃描或解析的bean只能是Spring內部所定義的,比如@Component、@Service、@Controller或@Repository。如果有一些自定義的註解,比如@Consumer、這個註解修飾的類是不會被掃描到的。這個時候我們就得自定義掃描器完成這個操作。

配置檔案中使用的:component-scan標籤底層使用ClassPathBeanDefinitionScanner這個類完成掃描工作的。@ComponentScan註解配合@Configuration註解使用,底層使用ComponentScanAnnotationParser解析器完成解析工作。

 

spring boot 啟動報錯

Caused by: java.lang.IllegalArgumentException: At least one JPA metamodel must be present!

估計是跟多個數據源有關,改成如下這樣就可以了
 

@SpringBootApplication  
@EnableAutoConfiguration(exclude={  
      JpaRepositoriesAutoConfiguration.class//禁止springboot自動載入持久化bean
        })  
@ImportResource({"classpath:spring-servlet.xml"})  
public class JzApplication {  
      
    public static void main(String[] args) throws Exception {  
        ApplicationContext ctx = SpringApplication.run(JzApplication .class,args);  
    }  
} 

 

目錄

Spring註解開發-全面解析常用註解使用方法


github位置:https://github.com/WillVi/Spring-Annotation/

1. @Configuration

​ @Configuration //配置註解類似 applicationcontext.xml 只是將xml配置改為 註解方式進行

2. @ComponentScan

進行包掃描會根據註解進行註冊元件,value="包名"

@ComponentScan(value="cn.willvi")

### FilterType

  • ANNOTATION 通過註解型別 列如 @Controller為Controller.class @Service 為 Service.class
  • ASSIGNABLE_TYPE, 一組具體類 例如PersonController.class
  • ASPECTJ, 一組表示式,使用Aspectj表示式命中類
  • REGEX 一組表示式,使用正則命中類
  • CUSTOM 自定義的TypeFilter.

excludeFilters

​ excludeFIlters = Filter[] 根據規則排除元件

@ComponentScan(value="cn.willvi",excludeFilters= {
        //根據註解排除註解型別為@Controller
        @Filter(type=FilterType.ANNOTATION,value= {Controller.class}),
        @Filter(type=FilterType.ASSIGNABLE_TYPE,value= {IncludeConfig.class,MainConfig.class}),
})

includeFilters

​ includeFIlters = Filter[] 根據規則只包含哪些元件(ps:useDefaultFilters設定為false

@ComponentScan(value="cn.willvi",includeFilters= {
        //根據註解型別掃描註解型別為@Controller的類
        @Filter(type=FilterType.ANNOTATION,value= {Controller.class})
},useDefaultFilters=false)

使用自定義TypeFilter

​ 當過濾有特殊要求時,可以實現TypeFilter來進行自定的過濾規則

自定義TypeFilter:

public class CustomTypeFilter implements TypeFilter {
    /**
     * metadataReader the metadata reader for the target class 讀取當前掃描類的資訊
     * metadataReaderFactory a factory for obtaining metadata readers
     * for other classes (such as superclasses and interfaces) 獲取其他類的資訊
     */
    public boolean match(MetadataReader reader, MetadataReaderFactory factory) throws IOException {
        //獲取當前掃描類資訊
        ClassMetadata classMetadata = reader.getClassMetadata();
        //獲取當前註解資訊
        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
        //獲取當前類資源(類路徑)
        Resource resource = reader.getResource();
        String className = classMetadata.getClassName();
        System.out.println("----->"+className);
        if(className.contains("PersonService")) {
            return true;
        }
        return false;
    }
}

使用:

//自定義過濾元件
@ComponentScan(value="cn.willvi",includeFilters= {
        @Filter(type=FilterType.CUSTOM,value= {CustomTypeFilter.class})
},useDefaultFilters=false)
//或者
//自定義過濾元件
@ComponentScan(value="cn.willvi",excludeFilters= {
        @Filter(type=FilterType.CUSTOM,value= {CustomTypeFilter.class})})

3. @Bean

​ 註冊bean與spring 的xml配置異曲同工之妙只是將xml配置轉換為註解

  <bean id="person" class="cn.willvi.bean.Person"  scope="prototype" >
        <property name="age" value="23"></property>
        <property name="name" value="willvi"></property>
    </bean>

@Scope

​ 在 Spring IoC 容器是指其建立的 Bean 物件相對於其他 Bean 物件的請求可見範圍。

  • singleton單例模式 全域性有且僅有一個例項

  • prototype原型模式 每次獲取Bean的時候會有一個新的例項

  • request 每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP request內有效

  • session session作用域表示該針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP session內有效

  • global session global session作用域類似於標準的HTTP Session作用域,不過它僅僅在基於portlet的web應用中才有意義。

    以上5個一般只用第一個和第二個

原型模式使用:

    @Bean
    @Scope("prototype")
    public Person person() {
        return new Person("willvi",23);
    }

驗證:

        ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class);
        Person person = (Person) ioc.getBean("personScope");
        Person person1 = (Person) ioc.getBean("personScope");
        //返回true說明為單例
        System.out.println(person==person1);

@Lazy

​ 懶載入。當Scope為單例模式時,當容器被初始化時就會被例項化。

​ 當有@Lazy時,在容器初始化時不會被例項化,在獲取例項時才會被初始化

單例模式懶載入使用

@Bean
    @Scope
    @Lazy //去掉和加上看輸出結果
    public Person person() {
        System.out.println("bean初始化");
        return new Person("willvi",23);
    }

驗證:

    ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class);
    System.out.println("容器初始化完成");
    Person person = (Person) ioc.getBean("personScope");

 參考:

https://blog.csdn.net/u014252478/article/details/83831224