一.Spring之组件注册bean

一.xml形式组件注册

pom

 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.5.RELEASE</version>
        </dependency>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="person" class="com.melo.bean.Person">
		<property name="name" value="张三"></property>
		<property name="age" value="18"></property>
	</bean>
</beans>

Person.java

package com.melo.bean;

public class Person {

	private String name;
	
	private Integer age;

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Person(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	
}

 test

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		//ClassPathXmlApplicationContext在类路径下读取xml文件
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
		//通过id获取
		Person bean = (Person) applicationContext.getBean("person");
		//通过class获取
		Person bean2 = applicationContext.getBean(Person.class);
		System.out.println(bean);
		System.out.println(bean2);
	}

二.配置类注册@Configuration@Bean

配置类,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")

//配置类=配置文件
@Configuration//告诉spring这是一个配置类
public class MyConfig {

	//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
	@Bean("person")
	public Person p1() {
		return new Person("李四", 26);
	}
}

test

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		//AnnotationConfigApplicationContext 获取配置类的容器
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		Person bean = (Person) applicationContext.getBean("person");
		System.out.println(bean);
		
		//获取此class在容器中的所有bean名字
		String[] names = applicationContext.getBeanNamesForType(Person.class);
		for(String name:names) {
			System.out.println(name);
		}
	}

三.指定扫描

1

@ComponentScan("com.melo") 扫描指定的包,会扫描@Controller @Service这些注解

//配置类=配置文件
@Configuration//告诉spring这是一个配置类
@ComponentScan("com.melo")
public class MyConfig {

	//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
	@Bean("person")
	public Person p1() {
		return new Person("李四", 26);
	}
}

@Controller
public class BookController {

}

@Repository
class BookDao {

}    

@Service
public class BookService {

}
public class IocTest {

	@SuppressWarnings("resource")
	@Test
	public void test1() {
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
		//所有定义的bean名字
		String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
		for(String name:beanDefinitionNames){
			System.out.println(name);
		}
	}
}

2.过滤扫描

@ComponentScan(value="com.melo",excludeFilters= {})

点击ComponentScan进入

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {

//指定只包括哪些
	Filter[] includeFilters() default {};

//指定过滤掉哪些
	Filter[] excludeFilters() default {};

}

发现可以按数组过滤,Filter数组,Filter也是注解

	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {

		/**
		 * The type of filter to use.
		 * <p>Default is {@link FilterType#ANNOTATION}.
		 * @see #classes
		 * @see #pattern
		 */
//按那种方式过滤,默认按注解
		FilterType type() default FilterType.ANNOTATION;
}

查看枚举FilterType


	//按注解排除
	ANNOTATION,

	//按类
	ASSIGNABLE_TYPE,

	/**
	 * Filter candidates matching a given AspectJ type pattern expression.
	 * @see org.springframework.core.type.filter.AspectJTypeFilter
	 */
	ASPECTJ,

	//正则
	REGEX,

//自定义
	CUSTOM

}

用注解排除试一下,排除controller 和Repository的注解

//配置类=配置文件
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo") 
@ComponentScan(value="com.melo",excludeFilters= {
		@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class})
		})
public class MyConfig {

	//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
	@Bean("person")
	public Person p1() {
		return new Person("李四", 26);
	}
}

在排除Service时出现了异常,Service is not assignable to interface Annotation还不知道原因

3.只包含扫描

includeFilters

默认规则就是扫描所有,只有禁用原规则,才能有效果,useDefaultFilters=false

//配置类=配置文件
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo") 
@ComponentScan(value="com.melo",includeFilters= {
		@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class})
		},useDefaultFilters=false)
public class MyConfig {

	//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
	@Bean("person")
	public Person p1() {
		return new Person("李四", 26);
	}
}

只有includeFilters指定的注解

4.多个扫描策略

@ComponentScans里面是数组,指定多个ComponentScan

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {

	ComponentScan[] value();

}
//配置类=配置文件
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo") 
@ComponentScans({
	@ComponentScan(value="com.melo",includeFilters= {
			@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class})
			},useDefaultFilters=false)
})
public class MyConfig {

	//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
	@Bean("person")
	public Person p1() {
		return new Person("李四", 26);
	}
}

5.其他过滤规则

最常用的是注解和类

FilterType.ASSIGNABLE_TYPE 按照类型过滤

@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo") 
@ComponentScans({
	@ComponentScan(value="com.melo",includeFilters= {
			@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class}),
			@Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {BookService.class})},
			useDefaultFilters=false)
})
public class MyConfig {

	//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
	@Bean("person")
	public Person p1() {
		return new Person("李四", 26);
	}
}

本来BookService在第一个Filter按注解方式没有包含,但在第二个Filter按类的方式包含了

试一下自定义规则,看注释说必须是TypeFilter的实现类

/** Filter candidates using a given custom
	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
	 */
	CUSTOM

 metadataReader 获取正在读取类的信息

metadataReaderFactory 一个工厂获取读到的其他类的信息

public interface TypeFilter {

	/**
	 * Determine whether this filter matches for the class described by
	 * the given metadata.
	 * @param metadataReader the metadata reader for the target class
	 * @param metadataReaderFactory a factory for obtaining metadata readers
	 * for other classes (such as superclasses and interfaces)
	 * @return whether this filter matches
	 * @throws IOException in case of I/O failure when reading metadata
	 */
	boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException;

}

实现一个TypeFilter,输出扫描到的类名

public class MyTypeFilter implements TypeFilter {

	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		//获取当前类的注解信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		//获取当前了类的类信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		//获取当前资源,类的路径	
		Resource resource = metadataReader.getResource();
		
		System.out.println(classMetadata.getClassName());
		return false;
	}

}

只使用自定义的过滤规则 

//配置类=配置文件
@Configuration//告诉spring这是一个配置类
//@ComponentScan("com.melo") 
@ComponentScans({
	@ComponentScan(value="com.melo",includeFilters= {
//			@Filter(type=FilterType.ANNOTATION,classes= {Controller.class,Repository.class})
//			,@Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {BookService.class})
			@Filter(type=FilterType.CUSTOM,classes= {MyTypeFilter.class})
			},
			useDefaultFilters=false)
})
public class MyConfig {

	//给容器注册一个bean,类型时返回值的类型,bean的id默认是方法名,想改名字可以改方法名,或者给@Bean(value="名字")
	@Bean("person")
	public Person p1() {
		return new Person("李四", 26);
	}
}

因为取消了默认扫描策略,所以controllerservice这些都不会注入容器,输出了扫描到的每个类名。又因为自定义扫描规则返回的全是false,所有不会有类被注入容器。myconfig和person是配置类本身的

更改自定义规则,将类名带"er"的返回true注入容器

public class MyTypeFilter implements TypeFilter {

	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();
		if(className.contains("er")) {
			return true;
		}
		return false;
	}

}

myConfig,person 不是包扫描结果不看。

注意:myTypeFilter虽然没有加注解,但符合我们的规则,并且@ComponentScan(value="com.melo" 扫描的是这个包,所以myTypeFilter也会被扫描到,并且注入

bookController bookService符合规则注入成功

四.@Scope设置作用域

@Bean默认是单实例

@Configuration
public class MyConfig2 {

        @Scope
	@Bean
	public Person person() {
		return new Person("james", 33);
	}
}

 输出true

	@SuppressWarnings("resource")
	@Test
	public void test2() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
		Object bean = applicationContext.getBean("person");
		Object bean2 = applicationContext.getBean("person");
		System.out.println(bean==bean2);
	}

查看@Scope

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

	/**
	 * Alias for {@link #scopeName}.
	 * @see #scopeName
	 */
	@AliasFor("scopeName")
	String value() default "";

	/**
	 * 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
	 * @see #value
	 */
	@AliasFor("value")
	String scopeName() default "";

* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE     ,prototype多实例
     * @see ConfigurableBeanFactory#SCOPE_SINGLETON   singleton单实例
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST  同一次请求
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION  同一个session

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {

	/**
	 * Scope identifier for the standard singleton scope: "singleton".
	 * Custom scopes can be added via {@code registerScope}.
	 * @see #registerScope
	 */
	String SCOPE_SINGLETON = "singleton";

	/**
	 * Scope identifier for the standard prototype scope: "prototype".
	 * Custom scopes can be added via {@code registerScope}.
	 * @see #registerScope
	 */
	String SCOPE_PROTOTYPE = "prototype";

 设置为多实例

@Configuration
public class MyConfig2 {

	@Scope(scopeName="prototype")
	@Bean
	public Person person() {
		return new Person("james", 33);
	}
}

单实例何时向容器注入对象?ioc开启时

@Configuration
public class MyConfig2 {

	@Scope(scopeName="singleton")
	@Bean
	public Person person() {
		System.out.println("给容器中注入对象person");
		return new Person("james", 33);
	}
}
@SuppressWarnings("resource")
	@Test
	public void test2() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);

	}

多实例何时向容器注入对象?从容器中获取时

@Configuration
public class MyConfig2 {

	@Scope(scopeName="prototype")
	@Bean
	public Person person() {
		System.out.println("给容器中注入对象person");
		return new Person("james", 33);
	}
}

@SuppressWarnings("resource")
	@Test
	public void test2() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
		Object bean = applicationContext.getBean("person");
		Object bean2 = applicationContext.getBean("person");
		System.out.println(bean==bean2);
	}

针对单实例的懒加载@Lazy,在第一次获取对象时才创建对象

@Configuration
public class MyConfig2 {

	//@Scope(scopeName="prototype")
	@Bean
	@Lazy
	public Person person() {
		System.out.println("给容器中注入对象person");
		return new Person("james", 33);
	}
}

五。@Conditional按条件注册

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
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();

}

可以看到Condition的属性value要求是实现Condition接口的class数组,此注解可以写在类上,也可以方法上。

Condition接口matches方法,匹配成功返回true,失败返回false

public interface Condition {

	/**
	 * Determine if the condition matches.
	 * @param context the condition context
	 * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
	 * or {@link org.springframework.core.type.MethodMetadata method} being checked.
	 * @return {@code true} if the condition matches and the component can be registered
	 * or {@code false} to veto registration.
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

写两个实现类。

//判断是否windows系统
public class WindowsConditional implements Condition {

	/**
	 * context: 判断条件使用的上下文环境
	 * metadata: 注释信息
	 */
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		
		//获取IOC使用的的=bean工厂
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//获取当前的环境信息
		Environment environment = context.getEnvironment();
		//获取bean定义的注册类,所有bean都在这定义,可以在里面取消bean、定义bean、查询bean
		BeanDefinitionRegistry registry = context.getRegistry();
		
		//os.name获取操作系统
		String property = environment.getProperty("os.name");
		if (property.contains("Windows"))
			return true;
		return false;
	}

}
//判断是否LINUX系统
public class LinuxConditional implements Condition {

	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		if (context.getEnvironment().getProperty("os.name").contains("Linux"))
			return true;
		return false;
	}

}

 在配置类的@bean加条件

@Configuration
public class MyConfig2 {

	//@Scope(scopeName="prototype")
	@Bean
	@Lazy
	public Person person() {
		System.out.println("给容器中注入对象person");
		return new Person("james", 33);
	}
	
	@Bean
	@Conditional(value= {WindowsConditional.class})
	public Person person1() {
		return new Person("bill", 50);
	}
	
	@Bean
	@Conditional(value= {LinuxConditional.class})
	public Person person2() {
		return new Person("linus", 60);
	}
}
	@Test
	public void test3() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
		String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
		for(String name:namesForType) {
			System.out.println(name);
		}
		
		Map<String, Person> map = applicationContext.getBeansOfType(Person.class);
		System.out.println(map);
	}

因为使用的是windows系统,所以WindowsConditional条件成功了

用RunConfigurations模拟linux

变成了LinuxConditional条件成功 

还可以写很多注册条件,比如已经有名为person的实例,就不注册了

public class WindowsConditional implements Condition {

	/**
	 * context: 判断条件使用的上下文环境
	 * metadata: 注释信息
	 */
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		
		//获取IOC使用的的=bean工厂
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//获取当前的环境信息
		Environment environment = context.getEnvironment();
		//获取bean定义的注册类,所有bean都在这定义,可以在里面取消bean、定义bean、查询bean
		BeanDefinitionRegistry registry = context.getRegistry();
		
		if(registry.containsBeanDefinition("person")) {
			return false;
		}
		
		//os.name获取操作系统
//		String property = environment.getProperty("os.name");
//		if (property.contains("Windows"))
//			return true;
		return false;
	}

}

如果@Conditional放在类上,就是这个条件成功时配置类里的bean才能注册,比如linux放在配置类上,如果是Windows系统,则这些bean都不会注册

@Configuration
@Conditional(value= {LinuxConditional.class})
public class MyConfig2 {

	//@Scope(scopeName="prototype")
	@Bean
	@Lazy
	public Person person() {
		System.out.println("给容器中注入对象person");
		return new Person("james", 33);
	}
	
	@Bean
	@Conditional(value= {WindowsConditional.class})
	public Person person1() {
		return new Person("bill", 50);
	}
	
	@Bean
	@Conditional(value= {LinuxConditional.class})
	public Person person2() {
		return new Person("linus", 60);
	}
}

六.@Import

1.快速导入一个组件

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

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

}

注释为Configuration、、ImportSelector、ImportBeanDefinitionRegistrar或者你直接要导入的class数组。

我们先直接导入

新建两个bean

public class Red {

}
public class Black {

}

配置类

@Configuration
@Import(value= {Red.class,Black.class})
public class MyConfig3 {

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

可以看到除了spring本身的注册实例和配置类实例,还有import的red、和black实例,并且实例名是类的全路径名

2.ImportSelector

刚刚看到@Import注解中除了导入还有其他方式。

ImportSelector接口,selectImports方法返回你要导入的类组件的全类名数组

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

}

实现这个接口,方法不能返回null会报错,可以返回空数组

public class MyImportSelector implements ImportSelector {

	/**
	 * 返回要导入的类的全类目数组
	 * importingClassMetadata:当前标注?@Import的类的所有注解信息,不仅是@Import其他注解也能看到
	 */
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {

		return new String[]{};
	}

}
@Configuration
@Import(value= {Red.class,Black.class,MyImportSelector.class})
public class MyConfig3 {

}

 debug可以看到参数是有标注@import的类上的所有注解的信息的,比如@Configuration

 

 返回一些要导入的类的全类名数组

public class MyImportSelector implements ImportSelector {

	/**
	 * 返回要导入的类的全类目数组
	 * importingClassMetadata:当前标注?@Import的类的所有注解信息,不仅是@Import其他注解也能看到
	 */
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {

		return new String[]{"com.melo.bean.Blue","com.melo.bean.Green"};
	}

}

可以看到Blue和Green实例被注册到容器,但不会注册MyImportSelector这个类

这个方式也是springboot自动配置实例的方式 ,读取factories文件中的信息,然后返回要注册的实例全类名数组springboot自定义自动配置_u014203449的博客-CSDN博客_springboot自定义自动配置

3.ImportBeanDefinitionRegistrar

前面的两个方法是把我们要注册的类名给spring让他去注册,ImportBeanDefinitionRegistrar是让我们自己注册

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
	 */
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

}

写个实现类,当容器中有名为com.melo.bean.Red和com.melo.bean.Black的实例,就去注册RainBow

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * AnnotationMetadata:当前类的注释信息
	 * BeanDefinition:注册类
	 * BeanDefinitionRegistry:通过registry。registerBeanDefinitions注册进去,也可以取消注册、查看注册情况
	 */
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		BeanDefinition BeanDefinition = new RootBeanDefinition(RainBow.class);
		if(registry.containsBeanDefinition("com.melo.bean.Red")&&
				registry.containsBeanDefinition("com.melo.bean.Black")) {
			registry.registerBeanDefinition("RainBow", BeanDefinition);
		}
	}

}

配置类

@Configuration
@Import(value= {Red.class,Black.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class MyConfig3 {

}

七.使用spring的FactoryBean(工厂bean)

public interface FactoryBean<T> {

	T getObject() throws Exception;

	Class<?> getObjectType();
	
	boolean isSingleton();

}

写个实现类,泛型写你想注册的类

public class ColorFactoryBean implements FactoryBean<Blue> {

        //得到bean实例
	public Blue getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Blue();
	}

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

        //单例还是多例
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return true;
	}

}
@Configuration
public class MyConfig4 {

	@Bean
	public ColorFactoryBean colorFactoryBean() {
		return new ColorFactoryBean();
	}
}

@Test
	public void testFactoryBean() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig4.class);
		Object bean = applicationContext.getBean("colorFactoryBean");
		System.out.println("bean的类型"+bean.getClass());
	}

虽然在配置类中,@Bean返回的是ColorFactoryBean,但可以看到产生的实例是Blue类型。

@Test
	public void testFactoryBean() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig4.class);
		Object bean = applicationContext.getBean("colorFactoryBean");
		System.out.println("bean的类型"+bean.getClass());
	
		Object bean2 = applicationContext.getBean("colorFactoryBean");
		System.out.println(bean==bean2);
	}

输出true,因为目前是单例的。

改为多例,就会输出false,两个对象不等

public class ColorFactoryBean implements FactoryBean<Blue> {


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

}

如果想获取工厂bean本身呢?用id获取,在实例名前加个&

Object bean3 = applicationContext.getBean("&colorFactoryBean");
		System.out.println(bean3.getClass());

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值