问题:
最近做项目的时候,需要引入其他的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");
参考: