给容器中注册组件的方法:
- @Bean注解方法返回实体注册, 一般在注册外部jar包中的类使用, 例如配置数据源DataSource…
- 包扫描(@ComponentScan)+组件标注注解(@Controller/@Sevice/@Respository/@Component)
- @Import或者实现ImportSeletor接口或者实现ImportBeanDefinitionRegistrar接口
- 实现FactoryBean接口, 再搭配使用@Bean注解注册实现类;
@Configuration & @Bean&@Scope&@Lazy
1. @Configuration
被@Configuration
注解标注的类, 则为一个配置类, 相当于xml
配置文件
@configuration
中有两个属性:
1).value
: @configuration
继承@component
, spring
会扫描所有被@component
注解的类, 认为这些类是bean, 需要注入容器中; 所以value
是用来指定这些类在容器中的id
值;
2).proxyBeanMethods
: 用来指定@Bean
注解标注的方法是否使用代理,默认是true
使用代理,直接从IOC容器之中取得对象;如果设置为false
,也就是不使用注解,每次调用@Bean
标注的方法获取到的对象和IOC容器中的都不一样,是一个新的对象,所以我们可以将此属性设置为false
来提高性能;
2. @Bean
被@Bean
标注的方法, 方法返回的实体类会注入IOC容器中;
属性:
1).value
: 指定bean
在容器中的id
值, 如果value
不指定值, 则默认以方法名为bean
的id
值;
2).initMethod
: 指定bean
的初始化方法;
3).destroyMethod
:指定bean
的销毁方法;
3. @Scope
指定bean
的作用域, 存在四种值,分别为 singleton 单例, prototype 多例, request 同一次请求内, session 同一个session内
;默认为singleton
单例模式;
若指定为 singleton
且不是懒加载(查看@Lazy
)的情况下, 则在容器启动时调用被@bean
标注的方法将bean
实例化, 之后获取bean
都是从容器中获取,且每次获取都是同一个实体;
若指定为prototype
, 则在获取bean
时调用被@bean
标注的方法获取bean
, 每次获取时都重新调用被@bean
标注的方法, 所以每次获取的bean
都是不同的;
4. @Lazy
指定作用域在单例模式下时是否启用懒加载, 默认是false
; 如果设置value=true
, 则在容器启动时, 不会实例化bean
; spring
会在第一次获取bean
的时候实例化bean
, 之后每次获取bean
都是从容器中获取,不在创建新的bean
;
// 告诉Spring这个类是一个配置类
@Configuration
public class SpringConfig {
// 将user注册至容器中 相当于xml配置文件中配置<bean id="user" class="xx.xx.xx.model.User"></bean>
@Bean
public User user() {
return new User();
}
@Bean
@Scope(value = "singleton") // 单例模式
@Lazy(value = true) // 启用懒加载
public Human human(){
return new Human();
}
/**
* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE prototype 多例
* @see ConfigurableBeanFactory#SCOPE_SINGLETON singleton 单例
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request 同一次请求内
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION session 同一个session内
*/
@Scope(value = "prototype") // 多例模式
@Bean(value="man", initMethod="personInit", destoryMethod="personDestory")
public Person person(){
return new Person();
}
}
@ComponentScan&@Filter&enum FilterType
1. @ComponentScan
在配置类上标注此注解, 配置spring
需要扫描的包路径, 将符合包路径条件且标注了@Controller/@Service/@Repository/@Component
等注解的类注册至容器中;
1).value
: 指定包扫描的路径;
2).includeFilters
:指定包含过滤条件, Filter数组类型, 配合@Filter注解使用;
3).excludeFilters
:指定排除过滤条件, Filter数组类型, 配合@Filter注解使用;
2. @Filter
用于@CmponentScan
注解中配置过滤条件
1).type
:指定过滤条件类型; 包含:①FilterType.ANNOTATION
注解类型;②FilterType.ASSIGNABLE_TYPE
指定明确类型; ③FilterType.ASPECTJ
使用ASPECTJ
表达式, 不常用;
④FilterType.REGEX
正则表达式,不常用;⑤FilterType.CUSTOM
自定义过滤条件类型, 需要创建一个实现了org.springframework.core.type.filter.TypeFilter
的类, 重写method
方法, 在方法中进行自定义匹配规则;
2)value
或classes
:根据指定过滤条件类型, 配置具体过滤的类, class<?>[]
数组类型;
@Configuration(value="config")
@ComponentScan(value = "study.bryan.spring",
excludeFilters = { // 排除
// 排除掉被@Controller注解标注的类
@Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
// 排除 PersonBookServiceImpl,BookServiceImpl这两个类
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {PersonBookServiceImpl.class, BookServiceImpl.class})
},
includeFilters = { // 包含
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookController.class}),
// 自定义规则 MyTypeFilter 实现TypeFilter接口, 根据match方法匹配
@Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}
)
public class SpringConfig {
@Bean
public User user() {
return new User();
}
}
/** 自定义TypeFilter 用于FilterType.CUSTOM类型过滤条件*/
import org.springframework.core.type.filter.TypeFilter;
public class MyTypeFilter implements TypeFilter{
/**
* metadataReader: 获取当前类的信息
* metadataReaderFactory: 获取其他类的信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// 获取当前扫描类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前扫描类的资源信息(例如类路径)
Resource resource = metadataReader.getResource();
// 获取当前扫描类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
String className = classMetadata.getClassName();
if (className.contains("Dao")) {
return true;
}
return false;
}
}
@Conditional
指定条件, 满足条件则将bean注入容器;
创建实现org.springframework.context.annotation.Condition
接口的类, 并重写matchs
方法, 即可将此类作为@Conditional
注解的value
条件值;
@Configuration
public class SpringConfig {
@Conditional({WinCondition.class})
@Bean(value = "bill")
public Person person01() {
return new Person();
}
@Conditional({LinuxCondition.class})
@Bean(value = "linus")
public Person person02() {
return new Person();
}
}
import org.springframework.context.annotation.Condition;
public class WinCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Win")) {
return true;
}
return false;
}
}
public class LinuxCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("linux")) {
return true;
}
return false;
}
}
@Import&ImportSeletor&ImportBeanDefinitionRegistrar
@Import
可以在配置类上直接指定需要注册至容器中的类, id
为全类名, 实现快速注册一个组件;
ImportSeletor
创建一个实现org.springframework.context.annotation.ImportSelector
接口的类, 重写selectImports
方法, 在方法中返回需要注册的组件的全类名数组, 搭配@Import注解, 可将返回数组中类注册至容器中;
ImportBeanDefinitionRegistrar
创建一个实现org.springframework.context.annotation.ImportBeanDefinitionRegistrar
接口的类, 重写registerBeanDefinitions
方法, 在方法中使用org.springframework.beans.factory.support.BeanDefinitionRegistry
类调用registerBeanDefinition()
方法将组件直接注册;最后搭配@Import
注解, 将自定义类放在@Import
注解的值中;
@Configuration
// Green类被直接以全类名方式注册至容器中
// MyImportSeletor中selectImports方法返回的全类名数组中的类被注册至容器中
// MyImportBeanDefinitionRegistar中registerBeanDefinitions方法手动注册了组件
@Import({Green.class, MyImportSeletor.class, MyImportBeanDefinitionRegistar.class})
public class SpringConfig {
...
}
/**实现ImportSelector接口, 在selectImports方法中返回组件全类名*/
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSeletor implements ImportSelector {
/**
* AnnotationMetadata 当前被标注@import注解的配置类信息
* @return 返回全类名数组, 不能为null
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
String[] arr = new String[] {
"study.bryan.spring.model.Blue",
"study.bryan.spring.model.Red"
};
return arr;
}
}
/**实现ImportBeanDefinitionRegistrar 接口,重写registerBeanDefinitions方法*/
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata 当前被标注@import注解的配置类信息
* BeanDefinitionRegistry BeanDefinition的注册类, 通过此类将组件手动注册至容器中
* @return 返回全类名数组, 不能为null
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// new一个BeanDefinition 这个类即是Spring中存放组件信息的类,
BeanDefinition beanDefinition = new RootBeanDefinition(Yellow.class);
registry.registerBeanDefinition("yellow", beanDefinition);
}
}
FactoryBean
实现org.springframework.beans.factory.FactoryBean<T>
接口, 重写接口的getObject和getObjectType方法;在配置类中使用@Bean注解将实现了FactoryBean接口的类注册;
@Configuration
public class SpringConfig {
// 这里的注册会将ColorFactoryBean 注册至容器中, 也会将ColorFactoryBean 中getObject方法返回的Color注册至容器中
// 其中Color的Id为colorFactoryBean, ColorFactoryBean 的id为&colorFactoryBean
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
}
import org.springframework.beans.factory.FactoryBean;
public class ColorFactoryBean implements FactoryBean<Color> {
public Color getObject() throws Exception {
// TODO Auto-generated method stub
return new Color();
}
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
}