@Configuration&@Bean
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
@Configuration
public class MainConfig {
@Bean
public Person person(){
return new Person("aaa",19);
}
}
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person bean = applicationContext.getBean(Person.class);
System.out.println(bean);
String[] names = applicationContext.getBeanNamesForType(Person.class);
System.out.println(Arrays.toString(names));
}
}
@ComponentScan自动扫描组件&指定扫描规则
@Test
public void test(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
指定排除规则:
@ComponentScan(value = "com.wj", excludeFilters = {
//按照注解类型去排除(排除标注Controller和Repository的类)
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class,Repository.class})
})
@ComponentScan(value = "com.wj", includeFilters = {
//按照注解类型去扫描(只扫描标注Controller和Repository的类)
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class,Repository.class})
},useDefaultFilters=false)
多组规则:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
此外,ComponentScan是一个可重复注解(jdk8),这也就意味着可以在一个类上可以标注多个ComponentScan来制定多组规则
TypeFilter指定过滤规则
按照指定的类型
public enum FilterType {
//按照注解
ANNOTATION,
//按照给定类型
ASSIGNABLE_TYPE,
//ASPECTJ表达式
ASPECTJ,
//正则指定
REGEX,
//自定义规则
CUSTOM
}
按照指定类型去扫描
@ComponentScan(value = "com.wj", includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = BookService.class)
},useDefaultFilters=false)
自定义filter:我们需要实现TypeFilter接口
/** Filter candidates using a given custom
* {@link org.springframework.core.type.filter.TypeFilter} implementation.
*/
CUSTOM
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader 读取到当前正在扫描的类的信息
* @param metadataReaderFactory 可以获取到其他任何类信息
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("classname-->"+className);
return false;
}
}
@ComponentScan(value = "com.wj", includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class)
},useDefaultFilters=false)
组件设置作用域@Scope
一般来说,放入IOC容器的bean都是单实例的
/**
* Specifies the name of the scope to use for the annotated component/bean.
* <p>Defaults to an empty string ({@code ""}) which implies
* {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
* @since 4.2
* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE 多实例的
* @see ConfigurableBeanFactory#SCOPE_SINGLETON 单实例的
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST 同一次请求创建一个实例
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION 同一个Session创建一个实例
* @see #value
*/
单实例:ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器中获取。
多实例:ioc容器启动并不会去调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象。
@Lazy懒加载
因为单实例对象默认在容器启动的时候创建对象。
使用@Lazy懒加载会在容器启动的时候不创建对象,需要使用的时候再创建对象
@Bean
@Lazy
public Person person(){
System.out.println("person实例创建了。。。。");
return new Person("aaa",19);
}
@Conditional按照条件注册
按照一定的条件进行判断,满足条件才注册bean。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//该注解可以加在类上和方法上
public @interface Conditional {
/**
* All {@link Condition}s that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
@Bean("bbb")
@Conditional(WindowsCondition.class)
public Person person01(){
return new Person("bbb",20);
}
@Bean("ccc")
@Conditional(LinuxCondition.class)
public Person person02(){
return new Person("ccc",21);
}
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
return property.contains("linux");
}
}
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
return property.contains("Windows");
}
}
我目前使用的是windows,进行测试:
@Test
public void test02(){
String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
}
@Import导入组件
@Configuration
//向IOC容器中导入Color组件,bean的id默认是组件的全类名
@Import(Color.class)
public class MainConfig2 {
}
@Test
public void testImport(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
Color bean = context.getBean(Color.class);
System.out.println(bean);
}
使用ImportSelector
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
测试:
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.wj.bean.Red","com.wj.bean.Person"};
}
}
@Configuration
@Import({Color.class, MyImportSelector.class})//向IOC容器中导入Color组件
public class MainConfig2 {
}
测试方法:
@Test
public void testImport(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
printBean(context);
}
public void printBean(ApplicationContext applicationContext){
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
使用ImportBeanDefinitionRegistrar
手动注册bean到容器中
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
//AnnotationMetadata 当前类的注解信息
//BeanDefinitionRegistry BeanDefinitionRegistry注册类
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
//如果容器中含有Red和Person,就往容器中导入blue
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean red = registry.containsBeanDefinition("com.wj.bean.Red");
boolean person = registry.containsBeanDefinition("com.wj.bean.Person");
if(red && person){
//指定bean的定义信息
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Blue.class);
registry.registerBeanDefinition("blue",rootBeanDefinition);
}
}
}
@Configuration
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})//向IOC容器中导入Color组件
public class MainConfig2 {
}
@Test
public void testImport(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
printBean(context);
}
执行结果:
FactoryBean注册组件
//创建一个spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean初始化。。。");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Configuration
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})//向IOC容器中导入Color组件
public class MainConfig2 {
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
@Test
public void testImport() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
Object bean = context.getBean("colorFactoryBean");
System.out.println(bean);
Object bean2 = context.getBean("&colorFactoryBean");
System.out.println(bean2);
}
在id前面加一个&符号,可以直接获取FactoryBean本身。这里在BeanFactory的源码中提到:
public interface BeanFactory {
/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from
* beans <i>created</i> by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
*/
String FACTORY_BEAN_PREFIX = "&";