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");
參考: