- 1.1、@Configuration + @Bean 为容器中注册组件
- 1.2、@ComponentScan 自动扫描组件&指定扫描规则
- 1.3、枚举类FilterType的其他过滤规则
- 1.4、@Scope设置组件作用域
- 1.5、@Lazy实现bean懒加载
- 1.6、@Condition按照条件注册bean
- 1.7、@Import给容器中快速导入一个组件
- 1.8、@Import使用ImportSelector
- 1.9、@Import使用ImportBeanDefinitionRegistrar
- 1.10、使用FactoryBean注册组件
1、组件添加
给容器中注册组件:
1、包扫描 + 组件标注注解(@Controller、@Service、@Repository、@Component)[局限于自己写的类]
2、@Bean[导入的第三方包里的组件]
3、@Import[快速给容器中导入一个组件]
3.1、@Import[要导入容器中的组件,容器就会自动注入这个组件,默认id为全类名]
3.2、ImportSelect导入选择器接口,里面有一个方法,返回字符串数组,由方法决定返回哪些组件
3.3、ImportBeanDefinitionRegistrar手工注册bean,相比前两种方法可以自定义bean名
4、使用Spring提供的FactoryBean[工厂bean]
4.1、默认获取到的是工厂bean调用getObject()创建的对象
4.2、要获取工厂bean本身,需要给id前增加"&"
1.1、@Configuration + @Bean 为容器中注册组件
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lwj</groupId>
<artifactId>spring-annotation</artifactId>
<version>1.0-SNAPSHOT</version>
<properties/>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
实体类:Person.java
package com.atguigu.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private String name;
private Integer age;
}
以前我们配置bean都是在applicationContext.xml配置文件中使用<bean>标签配置,现在使用JavaConfig的方式配置bean。
配置类:JavaConfig.java
package com.atguigu.config;
import com.atguigu.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//配置类(Java代码) == 配置文件(xml)
@Configuration
//告诉Spring,这是一个配置类
public class JavaConfig {
@Bean(value = "person")
//注册组件,<bean> -> @Bean,给容器中注册一个Bean,返回值类型为Bean类,id为方法名
//1、方法名作为bean的id;2、使用@Bean的value属性设置bean的id
//@Configuration + @Bean 给容器中注册组件
public Person person1() {
return new Person("李四", 22);
}
}
测试类:测试Bean容器中是否存在id=person的Person对象
package com.atguigu.test;
import com.atguigu.bean.Person;
import com.atguigu.config.JavaConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
public class MainTest {
//1、@Configuration + @Bean 为容器中注册组件
@Test
public void testAnnotation() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
Person person = (Person) context.getBean("person");
System.out.println(person);
//Person(name=李四, age=22)
String[] beanNamesForType = context.getBeanNamesForType(Person.class);
System.out.println(Arrays.toString(beanNamesForType));
//[person]
}
}
1.2、@ComponentScan 自动扫描组件&指定扫描规则
以前在xml文件中的扫描方式:引入context约束,<context:component-scan base-package="">,指定要扫描的包。现在使用JavaConfig方式自动扫描。
controller层
package com.atguigu.controller;
import org.springframework.stereotype.Controller;
@Controller
public class BookController {
}
service层
package com.atguigu.service;
import org.springframework.stereotype.Service;
@Service
public class BookService {
}
dao层
package com.atguigu.dao;
import org.springframework.stereotype.Repository;
@Repository
public class BookDao {
}
Person实体类使用@Configuration + @Bean的方式注入,而@Controller、@Service、@Repository这些都是@Component注解标注的(包括@Configuration),使用@ComponentScan自动扫描注入。
@ComponentScan注解:@Target(ElementType.TYPE),只能标注在类上,比如JavaConfig配置类上,@Repeatable(ComponentScans.class)可重复注解(jdk1.8新注解),在JavaConfig类上可以写多个@ComponentScan注解,扫描多个包,还有一点,@ComponentScan注解和@ComponentScans注解的@Retention和@Target必须相同,关于这一点,多看下注解的基础,尤其是@Repeatable注解的使用。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
在主配置类JavaConfig.java上配置@ComponentScan注解
package com.atguigu.config;
import com.atguigu.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(value = "com.atguigu.controller")
@ComponentScan(basePackages = {"com.atguigu.service", "com.atguigu.dao"})
//以上两种方式可以合并为@ComponentScan(value="com.atguigu"),上面的方式是为了体现@ComponentScan的元注解@Repeatable的作用
public class JavaConfig {
@Bean()
public Person person() {
return new Person("李四", 22);
}
}
测试类:测试容器中自动注入了哪些bean?
package com.atguigu.test;
import com.atguigu.bean.Person;
import com.atguigu.config.JavaConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
public class MainTest {
//<context:component-scan base-package="com.atguigu"> 在xml中配置包扫描,只要标注了
//@Controller、@Service、@Repository、@Component注解,都会被添加到容器中
//2、@ComponentScan,同样作用于配置类JavaConfig上
@Test
public void testComponentScan() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
//javaConfig
//bookController
//bookService
//bookDao
//person
//结果当然不包括IOC容器自动注入的一些bean
}
}
}
另外,在@ComponentScan自动扫描时,除了value和basePackages属性指定扫描哪些包以外,还可以制定扫描规则。
public @interface ComponentScan {
Filter[] includeFilters() default {};
Filter[] excludeFilters() default {};
}
excludeFilters属性指定扫描的时候排除哪些组件,类型为Filter数组。
这个Filter也是一个注解,可以指定type属性(按照什么规则,默认按照注解),value属性,是一个数组(注解.class)。
@interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
}
package com.atguigu.config;
import com.atguigu.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
@Configuration
@ComponentScan(value = {"com.atguigu"},
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})})
// 扫描com.atguigu的包,但是排除@Controller、@Service注解标注的类(当然可以不按照注解类型进行排除,默认是FilterType.ANNOTATION)
public class JavaConfig {
@Bean()
public Person person() {
return new Person("李四", 22);
}
}
测试@ComponentScan的excludeFilters属性,返回Filter类型的数组。
package com.atguigu.test;
import com.atguigu.bean.Person;
import com.atguigu.config.JavaConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
public class MainTest {
@Test
public void testComponentScan() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
//javaConfig
//bookDao
//person
}
}
}
从结果中可以看到excludeFilter的排除规则生效。
includeFilters:指定扫描的时候,只包含哪些组件。
现在重新修改JavaConfig.java配置类,让@ComponentScan自动扫描时只包含@Controller和@Service注解标注的类。
另外,在使用includeFilters属性只包含哪些注解时,要使默认扫描规则失效,(默认扫描所有组件),在ComponentScan中有一个属性,useDefaultFilters,默认为true,现在修改为false。
boolean useDefaultFilters() default true;
package com.atguigu.config;
import com.atguigu.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
@Configuration
@ComponentScan(value = {"com.atguigu"}, useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, Service.class})})
//只扫描标注了@Controller和@Service注解的类
public class JavaConfig {
@Bean()
public Person person() {
return new Person("李四", 22);
}
}
测试@ComponentScan的includeFilters属性:
package com.atguigu.test;
import com.atguigu.bean.Person;
import com.atguigu.config.JavaConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
public class MainTest {
@Test
public void testComponentScan() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
//javaConfig
//bookController
//bookService
//person
}
}
}
从结果可以看到确实@ComponentScan只扫描了标注Controller和Service的类。
1.3、枚举类FilterType的其他过滤规则
在上一节中使用@Filter(type=FilterType.ANNOTATION)按照注解类型进行过滤,现在学习其他过滤规则。
public enum FilterType {
ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM
}
FilterType.ASSIGNABLE_TYPE:按照给定的类型
JavaConfig.java
package com.atguigu.config;
import com.atguigu.bean.Person;
import com.atguigu.service.BookService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
@Configuration
@ComponentScan(value = {"com.atguigu"}, useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {BookService.class})})
//只扫描:1、@Controller注解标注的类;2、BookService的类及其子类
public class JavaConfig {
@Bean()
public Person person() {
return new Person("李四", 22);
}
}
测试:和@Filter(type=FilterType.ANNOTATION, value={Controller.class, Service.class})结果一致。
FilterType.ASPECTJ:按照ASPECTJ表达式(不常用)
FilterType.REGEX:按照正则表达式
FilterType.CUSTOM:按照自定义规则
要想自定义规则,那么必须实现TypeFilter
接口。
package com.atguigu.config;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader 读取到的当前正在扫描的类的信息
* @param metadataReaderFactory 可以获取到其他任何类的信息
* @return
* @throws IOException
*/
@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);
//return false;
//如果返回false时,那么includeFilters使用此规则后,容器中只有javaConfig和person
if (className.contains("er")) {
return true;
}
return false;
}
}
在JavaConfig中配置includeFilter的type类型为FilterType.CUSTOM,
package com.atguigu.config;
import com.atguigu.bean.Person;
import com.atguigu.service.BookService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
@Configuration
@ComponentScan(value = {"com.atguigu"}, useDefaultFilters = false,
includeFilters = {@Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})})
public class JavaConfig {
@Bean()
public Person person() {
return new Person("李四", 22);
}
}
测试方法:
@Test
public void testComponentScan() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
//javaConfig
//bookController
//bookService
//person
//myTypeFilter
}
}
除了@Configuration标注的JavaConfig类和@Bean标注的Person类之外,只有类名中包含"er"的类才会被@ComponentScan扫描到,包括MyTypeFilter类,这次扫描规则为自定义,和@Controller这类注解没有关系。
1.4、@Scope设置组件作用域
新建JavaConfig2类,
package com.atguigu.config;
import com.atguigu.bean.Person;
import org.springframework.context.annotation.*;
@Configuration
public class JavaConfig2 {
// prototype:多实例
// singleton:单实例(默认)
@Scope(value = "prototype")
@Bean
public Person person() {
return new Person("张三", 21);
}
}
@Scope("singleton") + @Bean 标注的person方法,IOC容器启动会调用方法创建对象,以后每次获取就是从容器中拿,每一次获取的都是同一个;
@Scope("prototype") + @Bean 标注的person方法,IOC容器启动不会调用方法创建对象,直到测试方法中getBean()主动获取时,才会创建对象,同时如果多次获取,每次不同。
1.5、@Lazy实现bean懒加载
懒加载针是对于单实例Bean来说,因为单实例Bean默认是在容器启动时创建对象。
所谓懒加载,即容器启动不创建对象,而在第一次使用/获取Bean时创建对象。
package com.atguigu.config;
import com.atguigu.bean.Person;
import org.springframework.context.annotation.*;
@Configuration
public class JavaConfig2 {
@Lazy
@Scope(value = "singleton")
@Bean
public Person person() {
return new Person("张三", 21);
}
}
1.6、@Condition按照条件注册bean
@Condition:按照一定的条件进行判断,满足条件给容器中注册Bean,不满足条件不注册,在SpringBoot底层大量使用。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition Conditions} that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
- @Condition注解 1、作用在类上;2、作用在方法上;
- value属性,类型为实现了Condition接口的类的class数组;
在IOC环境Environment对象中可以获取"os.name"操作系统名,可以根据操作系统名来决定将哪个bean注册到容器中。
WindowsCondition.java
package com.atguigu.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String property = context.getEnvironment().getProperty("os.name");
if ("Windows 10".equals(property)) {
return true;
}
return false;
}
}
LinuxCondition.java
package com.atguigu.condition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
BeanDefinitionRegistry registry = context.getRegistry();
//获取容器中bean的注册情况
boolean b = registry.containsBeanDefinition("person");
//判断容器中是否注册了id = person的bean,也可以给容器中注册bean
if ("Linux".equals(property)) {
return true;
}
return false;
}
}
JavaConfig2.java
package com.atguigu.config;
import com.atguigu.bean.Person;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.WindowsCondition;
import org.springframework.context.annotation.*;
@Configuration
public class JavaConfig2 {
@Bean
public Person person() {
return new Person("张三", 21);
}
@Conditional(value = {LinuxCondition.class})
@Bean(value = "shawnYue")
public Person person01() {
return new Person("ShawnYue", 32);
}
@Conditional(value = {WindowsCondition.class})
@Bean(value = "john")
public Person person02() {
return new Person("john", 23);
}
}
测试方法:
@Test
public void testConditional() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig2.class);
ConfigurableEnvironment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println(property); //Windows 10
String[] beanNamesForType = context.getBeanNamesForType(Person.class);
for (String name : beanNamesForType) {
System.out.println(name);
//person
//john
}
Map<String, Person> beans = context.getBeansOfType(Person.class);
System.out.println(beans);
//{person=Person(name=张三, age=21), john=Person(name=john, age=23)}
}
当@Condition注解作用于类上时,如果条件满足,那么该配置类下的bean可以注册;如果条件不满足,那么该配置类下的bean不可以注册,包括配置类本身。
@Conditional(value = {LinuxCondition.class})
@Configuration
public class JavaConfig2 {
}
测试方法:
String[] beanDefinitionNames = context.getBeanDefinitionNames();
System.out.println(Arrays.toString(beanDefinitionNames));
结果:都是Spring容器本身的Bean。
[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory]
1.7、@Import给容器中快速导入一个组件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
- @Import注解只能作用于配置类上,属性value类型为class的数组。
package com.atguigu.bean;
//Color类模拟框架/第三方包提供的类
public class Color {
}
package com.atguigu.bean;
public class Red {
}
在配置类上标注@Import注解
package com.atguigu.config;
import com.atguigu.bean.Color;
import com.atguigu.bean.Red;
import org.springframework.context.annotation.*;
@Configuration
@Import(value = {Color.class, Red.class})
public class JavaConfig2 {
}
测试方法:
@Test
public void testImport() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig2.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
//javaConfig2
//com.atguigu.bean.Color
//com.atguigu.bean.Red
}
}
1.8、@Import使用ImportSelector
package com.atguigu.condition;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
//自定义逻辑,返回需要导入的组件
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.atguigu.bean.Blue", "com.atguigu.bean.Yellow"};
}
}
package com.atguigu.bean;
//配合ImportSelector接口
public class Blue {
}
package com.atguigu.bean;
public class Yellow {
}
在配置类上添加ImportSelect
package com.atguigu.config;
import com.atguigu.bean.Color;
import com.atguigu.bean.Red;
import org.springframework.context.annotation.*;
@Configuration
@Import(value = {Color.class, Red.class, MyImportSelector.class})
public class JavaConfig2 {
}
测试方法:
@Test
public void testImport() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig2.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
//javaConfig2
//com.atguigu.bean.Color
//com.atguigu.bean.Red
//com.atguigu.bean.Blue
//com.atguigu.bean.Yellow
}
}
从运行结果可以看到,导入容器的是返回的全类名数组,而不是MyImportSelector类。
1.9、@Import使用ImportBeanDefinitionRegistrar
package com.atguigu.condition;
import com.atguigu.bean.Rainbow;
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 MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean red = registry.containsBeanDefinition("com.atguigu.bean.Red");
boolean blue = registry.containsBeanDefinition("com.atguigu.bean.Blue");
if (red && blue) {
registry.registerBeanDefinition("rainbow", new RootBeanDefinition(Rainbow.class));
}
}
}
package com.atguigu.bean;
public class Rainbow {
}
配置类上标注ImportBeanDefinitionRegistrar
package com.atguigu.config;
import com.atguigu.bean.Color;
import com.atguigu.bean.Red;
import org.springframework.context.annotation.*;
@Configuration
@Import(value = {Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegister.class})
public class JavaConfig2 {
}
测试方法:
@Test
public void testImport() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig2.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
//javaConfig2
//com.atguigu.bean.Color
//com.atguigu.bean.Red
//com.atguigu.bean.Blue
//com.atguigu.bean.Yellow
//rainbow
}
}
1.10、使用FactoryBean注册组件
package com.atguigu.bean;
import org.springframework.beans.factory.FactoryBean;
//创建一个Spring定义的工厂bean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
System.out.println("调用了ColorFactoryBean的getObject()方法");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
//是否单例?
//true:这个bean是单实例,在容器中只存在一份
//false:这个bean是多实例,每次获取都会创建一个新的
@Override
public boolean isSingleton() {
return true;
}
}
在配置类中添加注册FactoryBean对象
package com.atguigu.config;
import com.atguigu.bean.ColorFactoryBean;
import org.springframework.context.annotation.*;
@Configuration
public class JavaConfig2 {
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
}
测试方法:
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig2.class);
//工厂bean调用的是getObject()方法创建的对象
Object colorFactoryBean = context.getBean("colorFactoryBean");
System.out.println(colorFactoryBean.getClass());
//调用了ColorFactoryBean的getObject()方法
//class com.atguigu.bean.Color
//如果想要获取ColorFactoryBean的对象
Object bean = context.getBean("&colorFactoryBean");
System.out.println(bean.getClass());
//class com.atguigu.bean.ColorFactoryBean
}
虽然注册的是ColorFactoryBean,但是默认获取到的是Color实例。