【Spring注解】1、Spring组件注册

7 篇文章 0 订阅

1、@Configuration:

指定该注解的类是个配置类,对应之前的配置文件

 

2、@Bean:

指定该方法作为一个Bean组件,它会往容器中注册一个Bean组件;

其中类型为返回值,id默认为方法名;

也可以使用@Bean注解的name属性,来自定义id。

 

 

3、@ComponentScans:

可以配置多个@ComponentScan

3.1、@ComponentScan:

指定要扫描的包路径

  • excludeFilters=Filter[]: 指定扫描的时候要排除的组件。

  • useDefaultFilters: 过滤策略,默认为true,即会自动扫描带@Component注解(包括@Component@Controller@Service@Repository注解的类)。

  • includeFilters=Filter[]: 指定扫描符合规则的组件,如果只是想扫描某些指定组件,需要将useDefaultFilters设为false,禁用默认的扫描策略。

 

3.1.1、Filter类型:

  • FilterType.ANNOTATION: 按照注解
@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})

        使用@Controller注解的类符合以上规则。

 

  • FilterType.ASSIGNABLE_TYPE: 按照给定的类型
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = xxx.class)

        符合xxx.java的类符合以上规则。

 

  • FilterType.ASPECTJ: 按照ASPECTJ表达式
  • FilterType.REGEX: 按照正则表达式
  • FilterType.CUSTOM: 使用自定义规则

        要使用该策略,类必须实现org.springframework.core.type.filter.TypeFilter接口。

public class MyTypeFilter implements TypeFilter {

	/**
	 * metadataReader: 读取到的当前正在扫描的类信息
	 * metadataReaderFactory: 可以获取到其他任何类信息的工厂类
	 */
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		// TODO Auto-generated method stub
		//获取当前类注解的信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		
		//获取当前正在扫描的类信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		
		//获取当前类的资源(类路径)
		Resource resource = metadataReader.getResource();
		
		String className = classMetadata.getClassName();
		System.out.println(">>>>>" + className);
		//简单测试,如果扫描的类名中包含了er,则匹配
		if(className.contains("er")){
			return true;
		}
		return false;
	}
}

同时标注:

@Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})

        这样,在扫描的时候会将包含"er"字母的类加入到容器中。

 

4、@Scope:

指定组件的作用域,默认为单例:singleton

singleton:单实例,当ioc容器启动会调用方法创建对象并放到ioc容器中,而以后每次获取对象的时候直接从ioc容器中获取。

prototype:多实例,ioc容器启动并不会去调用方法创建对象,而是在每次获取的时候才会去调用方法创建对象,所以每次获取的对象都是不一样的。

@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public Book book(){
    System.out.println("创建book实例...");
    return new Book();
}

@Bean
public Person person(){//默认单实例
    System.out.println("创建person实例...");
    return new Person("zhangsan", 20);
}

测试:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);

//单实例
Object obj1 = applicationContext.getBean("person");
Object obj2 = applicationContext.getBean("person");
System.out.println(obj1 == obj2);//输出true

//多实例
Object obj3 = applicationContext.getBean("book");
Object obj4 = applicationContext.getBean("book");
System.out.println(obj3 == obj4);//输出false

 

5、@Lazy:

懒加载:只针对于单实例对象

默认加载Bean是在容器启动的时候就会去创建对象,并将其放入ioc容器中;而懒加载则相反,容器启动时不创建对象,而是在第一次使用(获取)对象的时候,才会去创建对象,再将其加入到ioc容器中,之后每次再获取该对象的时候,直接从ioc容器中获取,不再重新创建。

@Lazy
@Bean
public Book book2(){
    System.out.println("创建book2实例...");
    return new Book();
}

 

6、@Conditional:

该注解可以标注在类上,也可以标注在方法上

方法级别:根据条件创建bean,只有满足条件才会创建bean;

类级别:根据条件创建配置类,只有满足条件才会去创建配置类,如果不满足,则不会创建该配置类,同时配置类里的bean也就不会被创建。

配置类:

@Configuration
public class MyConfig3 {

	@Conditional(WindowsCondition.class)
	@Bean("bill")
	public Person person1(){
		return new Person("bill gates", 60);
	}
	
	@Conditional(LinuxCondition.class)
	@Bean("linus")
	public Person person2(){
		return new Person("linus", 50);
	}
}

 LinuxCondition条件类:

//判断是否是Linux系统
public class LinuxCondition implements Condition{

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO Auto-generated method stub
		//获取到ioc使用的BeanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		
		//获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		
		//获取当前环境变量
		Environment environment = context.getEnvironment();
		
		//获取到bean定义的注册类
		BeanDefinitionRegistry registry = context.getRegistry();
		
		//获取系统环境
		String systemName = environment.getProperty("os.name");
		if(systemName.contains("Linux")){
			return true;
		}
		return false;
	}

}

WindowsCondition条件类:

//判断是否是Windows系统
public class WindowsCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO Auto-generated method stub
		// 获取当前环境变量
		Environment environment = context.getEnvironment();
		// 获取系统环境
		String systemName = environment.getProperty("os.name");
		if (systemName.contains("Windows")) {
			return true;
		}
		return false;
	}

}

这样,使用不同的操作系统,创建的Bean也就不一样。

 

7、Spring导入组件的方式:

Spring导入组件的方式:

1、使用注解@Component@Controller@Service@Repository

2、使用@Bean导入第三方组件

3、使用@Import快速导入一个或多个第三方组件

3.1、指定类

3.2、使用ImportSelector接口

3.3、使用ImportBeanDefinitionRegistrar接口

4、 FactoryBean接口

 

7.1、@Import

7.1.1、指定类

假设有两个颜色类:Red.java和Green.class,可以在配置类上使用@Import注解注册该两个类。

@Import({Red.class, Green.class})

这样在Bean定义的注册表里有其两个组件,其组件的id为全类名

 

7.1.2、ImportSelector接口

需要实现ImportSelector接口

public class MyImportSelector implements ImportSelector {

	//返回值就是要导入到容器中的组件全类名
	//AnnotationMetadata:当前标注@Import注解的类的所有注解信息
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// TODO Auto-generated method stub
		//方法不要返回null
		return new String[]{"org.com.cay.spring.annotation.color.Blue", "org.com.cay.spring.annotation.color.Yellow"};
	}
}

导入:

@Import({Red.class, Green.class, MyImportSelector.class})

这样不仅会将@Import注解中指定的类加入到容器中,同样会将MyImportSelector#selectImports中方法返回的全类名进行注册到容器中。

 

7.1.3、ImportBeanDefinitionRegistrar接口

实现ImportBeanDefinitionRegistrar接口,实现registerBeanDefinitions方法,手动注册bean。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * AnnotationMetadata:当前类的注解信息
	 * 
	 * BeanDefinitionRegistry:BeanDefinition注册类
	 * 		把所有需要添加到容器中的bean,手动通过{@link BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)}进行注册
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// TODO Auto-generated method stub

        //因为Yellow这个Bean是通过@Import导入的,所以bean的id为全类名,所以这里需要判断全类名才行
		boolean hasBean = registry.containsBeanDefinition("org.com.cay.spring.annotation.color.Yellow");
		System.out.println(">>>>>>hasBean: " + hasBean);
		if(hasBean){
			BeanDefinition beanDefinition = new RootBeanDefinition(Tiger.class);
			registry.registerBeanDefinition("tiger", beanDefinition);
		}
	}
}

添加该实现类到@Import属性中:

@Import({ Red.class, Green.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class }) 

 

7.2、FactoryBean接口

实现FactoryBean接口

public class ColorFactory implements FactoryBean<Color>{

	//返回一个Color对象,这个对象会添加到容器中
	@Override
	public Color getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Color();
	}

	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Color.class;
	}

	@Override
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return true;
	}
}

并将该factoryBean注册到容器中:

@Configuration
@Import({ Red.class, Green.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class })
public class MyConfig4 {

	@Bean
	public ColorFactory colorFactory(){
		return new ColorFactory();
	}
}

测试:

@Test
public void testFactoryBean(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig4.class);
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    Arrays.asList(beanDefinitionNames).stream().forEach(System.out::println);

	//获取到的是实现FactoryBean接口后通过getObject返回的实际bean
    Object bean = applicationContext.getBean("colorFactory");
    System.out.println("bean的类型: " + bean.getClass());
    
    //获取factorybean自身bean
    //org.springframework.beans.factory.BeanFactory.FACTORY_BEAN_PREFIX = "&";
    Object bean2 = applicationContext.getBean("&colorFactory");
    System.out.println("bean2的类型: " + bean2.getClass());
}

为何使用"&"?

package org.springframework.beans.factory;
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 = "&";
    
    //other...
}

 

 

====================打个广告,欢迎关注====================

QQ:

412425870

微信公众号:Cay课堂

csdn博客:

http://blog.csdn.net/caychen

码云:

https://gitee.com/caychen/

github:

https://github.com/caychen

点击群号或者扫描二维码即可加入QQ群:

328243383(1群)

 

点击群号或者扫描二维码即可加入QQ群:
180479701(2群)

--------------------- 作者:caychen 来源:CSDN 原文:https://blog.csdn.net/caychen/article/details/82887926?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值