Spring注解(五):容器注册组件的四种方式

81 篇文章 5 订阅
18 篇文章 1 订阅

将自定义的Bean注册到容器中有四种方式:

1、使用@Bean注解:

Spring注解(一):@Configuration、@Bean给容器中注册组件

2、使用包扫描、组件标注注解的方式

采用@Controller/@Service/@Repository/@Component注解,这种方式只局限于自己写的类,不能用于导入第三方包:
Spring注解(二):@ComponentScan自动扫描组件

3、使用@import注册组件:

声明一个Role类:

package com.xinyi.bean;

public class Role {
}

通过测试类输出容器中注入的bean:

@Test
	public void test4() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig1.class);
		String[] names = applicationContext.getBeanDefinitionNames();
		for(String name:names) {
			System.out.println(name);
		}
	}

在这里插入图片描述
Role并没有被注入进IOC容器。

在配置类上添加:@Import(Role.class),代码如下:

@Configuration
@Import(Role.class)
public class MyConfig1 {
	@Bean("Lin Sin")
	@Lazy
	public Person person() {
		return new Person("李青",18);
	}
	@Bean("Yasuo")
	public Person person1() {
		return new Person("亚索",23);
	}
	@Bean("Zed")
	public Person person2() {
		return new Person("劫",32);
	}
}

此时Role被注入进了IOC容器,id为类的全类名。
在这里插入图片描述
这里使用的时@注解,import注解的源码如下:

public @interface Import {

	/**
	 * {@link Configuration @Configuration}, {@link ImportSelector},
	 * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
	 */
	 //数组
	Class<?>[] value();

}

根据源码可以发现@import注解后面的参数值可以是数组,所以使用@import注解可以同时注入多个组件,比如@Import(Role1.class,Role2.class,......)

除了直接使用@import注解之外,还可使用ImportSelector(导入选择器)来根据条件进行注册bean,ImportSelector返回需要注册的全类名,这也是SpringBoot开发中bean注册的主要方式。
声明一个MyImportSelector类并实现ImportSelector接口,自定义导入选择器,返回需要注册的组件。

//自定义导入选择器,返回需要注册的组件
public class MyImportSelector implements ImportSelector {
	
	//返回值就是匹配的要注册的组件(全类名)
	//AnnotationMetadata:当前标注@import注解的类的所有注解信息
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		return new String[]{"com.xinyi.bean.Role1","com.xinyi.bean.Role2"};
	}
}

ImportSelector 接口的源码如下,返回的是一个string数组,数组中就是匹配的要注册的组件(全类名):

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);

}

在注册类中@import注解添加MyImportSelector:

@Import(Role.class,MyImportSelector.class)

返回结果如下,Role1和Role2被注入IOC容器中,bean的名称则是组件全类名。
在这里插入图片描述

另外还可以使用ImportBeanDefinitionRegistrar接口来手动自定义注册的bean名称。
新建一个Role3类和MyImportBeanDefinitionRegistrar 类并实现ImportBeanDefinitionRegistrar接口:

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{
	/**
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:bean定义的注册类信息
	 * 需要注册到容器中的bean调用BeanDefinitionRegistry.registryBeanDefinition
	 */
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//设置注入条件:containsBeanDefinition的参数是组件的全类名
		boolean flag = registry.containsBeanDefinition("com.xinyi.bean.Role");
		//如果容器中包含Role组件,则将Role3注入进IOC容器
		if(flag) {
			RootBeanDefinition beanDefinition = new RootBeanDefinition(Role3.class);
			registry.registerBeanDefinition("自定注入的Bean名称", beanDefinition);
		}
	}
}

在注册类文件中的@import注解增加MyImportBeanDefinitionRegistrar.class参数

@Import({Role.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})

因为包含了com.xinyi.bean.Role,所以Role3组件也被注入进容器,并且组件的名称是自定了的bean的名称(自定义注入的bean的名称)。
在这里插入图片描述

4、使用spring提供的FactoryBean进行组件注册

声明一个RoleBean类并实现FactoryBean接口

//创建spring定义的FactoryBean类
public class RoleBean implements FactoryBean<Role> {
	//返回一个role对象并添加到容器中
	public Role getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Role();
	}
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Role.class;
	}

}

FactoryBean接口的源码如下:

public interface FactoryBean<T> {

	/**
	 * Return an instance (possibly shared or independent) of the object
	 * managed by this factory.
	 * <p>As with a {@link BeanFactory}, this allows support for both the
	 * Singleton and Prototype design pattern.
	 * <p>If this FactoryBean is not fully initialized yet at the time of
	 * the call (for example because it is involved in a circular reference),
	 * throw a corresponding {@link FactoryBeanNotInitializedException}.
	 * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
	 * objects. The factory will consider this as normal value to be used; it
	 * will not throw a FactoryBeanNotInitializedException in this case anymore.
	 * FactoryBean implementations are encouraged to throw
	 * FactoryBeanNotInitializedException themselves now, as appropriate.
	 * @return an instance of the bean (can be {@code null})
	 * @throws Exception in case of creation errors
	 * @see FactoryBeanNotInitializedException
	 */
	@Nullable
	T getObject() throws Exception;

	/**
	 * Return the type of object that this FactoryBean creates,
	 * or {@code null} if not known in advance.
	 * <p>This allows one to check for specific types of beans without
	 * instantiating objects, for example on autowiring.
	 * <p>In the case of implementations that are creating a singleton object,
	 * this method should try to avoid singleton creation as far as possible;
	 * it should rather estimate the type in advance.
	 * For prototypes, returning a meaningful type here is advisable too.
	 * <p>This method can be called <i>before</i> this FactoryBean has
	 * been fully initialized. It must not rely on state created during
	 * initialization; of course, it can still use such state if available.
	 * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
	 * {@code null} here. Therefore it is highly recommended to implement
	 * this method properly, using the current state of the FactoryBean.
	 * @return the type of object that this FactoryBean creates,
	 * or {@code null} if not known at the time of the call
	 * @see ListableBeanFactory#getBeansOfType
	 */
	@Nullable
	Class<?> getObjectType();

	/**
	 * Is the object managed by this factory a singleton? That is,
	 * will {@link #getObject()} always return the same object
	 * (a reference that can be cached)?
	 * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
	 * the object returned from {@code getObject()} might get cached
	 * by the owning BeanFactory. Hence, do not return {@code true}
	 * unless the FactoryBean always exposes the same reference.
	 * <p>The singleton status of the FactoryBean itself will generally
	 * be provided by the owning BeanFactory; usually, it has to be
	 * defined as singleton there.
	 * <p><b>NOTE:</b> This method returning {@code false} does not
	 * necessarily indicate that returned objects are independent instances.
	 * An implementation of the extended {@link SmartFactoryBean} interface
	 * may explicitly indicate independent instances through its
	 * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
	 * implementations which do not implement this extended interface are
	 * simply assumed to always return independent instances if the
	 * {@code isSingleton()} implementation returns {@code false}.
	 * <p>The default implementation returns {@code true}, since a
	 * {@code FactoryBean} typically manages a singleton instance.
	 * @return whether the exposed object is a singleton
	 * @see #getObject()
	 * @see SmartFactoryBean#isPrototype()
	 */
	 //默认是true:Bean是单例,在容器中保存一份
	 //当为false:多实例,每次创建都会获取一个新的bean
	default boolean isSingleton() {
		return true;
	}

接着在配置类中注册RoleBean

@Bean
	public RoleBean roleBean() {
		return new RoleBean();
	}

在测试方法中添加下述代码返回RoleBean的类型

Object beanObject = applicationContext.getBean("roleBean");
		System.out.println("roleBean的类型是:"+beanObject.getClass());

RoleBean的类型是Role,因为RoleBean调用的是getObject方法创建的对象,而getObject方法返回的是new Role()。
在这里插入图片描述
可以通过在RoleBean组件名称前加“&”符号来表明注册的是RoleBean组件本身。

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.
	 */
	 //factorybean前缀符:返回的是工厂类,而不是调用getObject方法产生的对象
	String FACTORY_BEAN_PREFIX = "&";
Object beanObject1 = applicationContext.getBean("&roleBean");
System.out.println("获取roleBean本身:"+beanObject1.getClass());

在这里插入图片描述
以上就是在IOC容器中进行组件注册的四种方式。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值