Spring注解驱动开发之常用注解案例_告别在XML中配置Bean

Spring注解驱动开发之常用注解案例

文章目录

  • Spring注解驱动开发之常用注解案例
  • [1. 组件注册注解](#1. 组件注册注解)
    • [1.1 @Configuration和@Bean注解](#1.1 @Configuration和@Bean注解)
    • [1.2 自动扫描组件和指定扫描规则](#1.2 自动扫描组件和指定扫描规则)
    • [1.3 自定义TypeFilter指定过滤规则](#1.3 自定义TypeFilter指定过滤规则)
    • [1.4 @Scope设置组件的作用域](#1.4 @Scope设置组件的作用域)
    • [1.5 @Lazy注解,bean懒加载注解](#1.5 @Lazy注解,bean懒加载注解)
    • [1.6 @Conditional-按照条件注册bean](#1.6 @Conditional-按照条件注册bean)
  • [2. 给容器中注册组件的方式](#2. 给容器中注册组件的方式)
    • [2.1 包扫描+组件标注注解](#2.1 包扫描+组件标注注解)
    • [2.2 @Bean](#2.2 @Bean)
    • [2.3 @Import[快速给容器中导入一个组件]](#2.3 @Import[快速给容器中导入一个组件])
      • [2.3.1 @Import(要导入到容器中的组件)](#2.3.1 @Import(要导入到容器中的组件))
      • [2.3.2 ImportSelector:返回需要导入的组件的全类名数组;](#2.3.2 ImportSelector:返回需要导入的组件的全类名数组;)
      • [2.3.3 ImportBeanDefinitionRegistrar:手动注册bean到容器中](#2.3.3 ImportBeanDefinitionRegistrar:手动注册bean到容器中)
    • [3.使用Spring提供的 FactoryBean(工厂Bean);](#3.使用Spring提供的 FactoryBean(工厂Bean);)
      • [3.1 默认获取到的是工厂bean调用getObject创建的对象](#3.1 默认获取到的是工厂bean调用getObject创建的对象)
      • [3.2 要获取工厂Bean本身,要获取工厂Bean本身,我们需要给id前面加一个&,如:&colorFactoryBean](#3.2 要获取工厂Bean本身,要获取工厂Bean本身,我们需要给id前面加一个&,如:&colorFactoryBean)

注解驱动开发就是不再使用Spring的bean.xml文件,改为纯使用注解的方式开发

1. 组件注册注解

1.1 @Configuration和@Bean注解

  1. @Configuration

    此注解为配置类注解,相当于spring.xml文件,即配置类==配置文件

  2. @Bean

    给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id

  • 示例
java 复制代码
package com.yuan.annotation.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.yuan.annotation.bean.Person;

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
public class MainConfig {
	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
	@Bean("person")
	public Person personA() {
		return new Person(1,"张三",33);
	}
}

Person类(后续注解配置类中都会以此类举例),Person.java

java 复制代码
package com.yuan.annotation.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
public class Person {
	private Integer id;
	private String name;
	private Integer age;
}

测试类

java 复制代码
package com.yuan.annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.yuan.annotation.bean.Person;
import com.yuan.annotation.config.MainConfig;

public class MainTest {
	private static ApplicationContext applicationContext;

	public static void main(String[] args) {
		applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		/*
		 * Person person = applicationContext.getBean(Person.class);
		 * System.out.println(person);
		 */
		
		String [] nameTypes =  applicationContext.getBeanNamesForType(Person.class);
		
		for(String s : nameTypes) {
			System.out.println(s);
		}
		
		Person person = (Person) applicationContext.getBean("person");
		System.out.println(person);
	}
}

1.2 自动扫描组件和指定扫描规则

  1. @ComponentScan 自动扫描组件注解,jdk8+版本,此注解可以在同一个类上多写几次,jdk8以下版本可以使用@ComponentScans注解

jdk8+版本示例

java 复制代码
//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
@ComponentScan(value = "com.yuan.annotation",includeFilters= {
		@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters=false) //指定要扫描的包
@ComponentScan(.....)
@ComponentScan(.....)
@ComponentScans(value = { @ComponentScan(value="xx.xxx") })
public class MainConfig {
	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
	@Bean("person")
	public Person personA() {
		return new Person(1,"张三",33);
	}
}

jdk8以下版本示例

java 复制代码
//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
@ComponentScans(value = { @ComponentScan(value="xx.xxx") })
public class MainConfig {
	...
}
  • value:数组类型,指定要扫描的包

  • includeFilters:Filter数组类型,指定扫描时包含哪些组件,使用此属性时,@ComponentScan的useDefaultFilters属性值设置false才能起作用,即useDefaultFilters=false;useDefaultFilters=true为默认值,扫描所有

  • excludeFilters:Filter数组类型,指定扫描时排除哪些组件

java 复制代码
package com.yuan.annotation.config;

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.context.annotation.ComponentScan.Filter;

import com.yuan.annotation.bean.Person;

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
//@ComponentScan(value= {"com.yuan.annotation.bean","com.yuan.annotation.dao","com.yuan.annotation.service"})
@ComponentScan(value = "com.yuan.annotation",includeFilters= {
		@Filter(type = FilterType.ANNOTATION,classes = Controller.class)
}) //指定要扫描的包


public class MainConfig {
	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
	@Bean("person")
	public Person personA() {
		return new Person(1,"张三",33);
	}
}

1.3 自定义TypeFilter指定过滤规则

  • FilterType.ANNOTATION:按照注解(常用)
  • FilterType.ASSIGNABLE_TYPE:按照指定的类型(常用)
  • FilterType.ASPECTJ:使用ASPECTJ表达式
  • FilterType.CUSTOM:使用用户自定义规则
  • FilterType.REGEX:使用正则表达式
  1. 自定义规则类,如:MyTypeFilter.java
  • 自定义过滤规则类需要实现TypeFilter接口
java 复制代码
package com.yuan.annotation.config;

import java.io.IOException;

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;

public class MyTypeFilter implements TypeFilter {
    
	/*
	 * metadataReader:读取到的当前正在扫描的类
	 * 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中包含er,表示匹配成功
		if(className.contains("er")) {
			return true;
		}
		return false;
	}
}
  1. 配置类,MainConfig.java
java 复制代码
package com.yuan.annotation.config;

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.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.ComponentScans;

import com.yuan.annotation.bean.Person;
import com.yuan.annotation.service.BookService;

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
@ComponentScan(value = "com.yuan.annotation",includeFilters= {
		@Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
},useDefaultFilters=false) //指定要扫描的包

@ComponentScans(value = { @ComponentScan(value="xx.xxx") })
public class MainConfig {
	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
	@Bean("person")
	public Person personA() {
		return new Person(1,"张三",33);
	}
}
  1. 测试类IOCTest.java
java 复制代码
package com.yuan.annotation.test;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.yuan.annotation.config.MainConfig;

public class IOCTest {
	private AnnotationConfigApplicationContext applicationContext;

	@Test
	public void test01() {
		applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		
		String [] definitionNames =  applicationContext.getBeanDefinitionNames();
		
		for(String beanName : definitionNames) {
			System.out.println(beanName);
		}
	}
}
  1. 打印结果:
java 复制代码
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
mainConfig
person
myTypeFilter
bookController
bookService

1.4 @Scope设置组件的作用域

  1. 配置类,ScopeConfig.java
java 复制代码
package com.yuan.annotation.config;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import com.yuan.annotation.bean.Person;

@Configuration
public class ScopeConfig {
	/**
	 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
	 * 
	 * singleton: 单实例(默认),IOC容器启动时会调用方法创建对象放到IOC容器中
	 * prototype: 多实例的,IOC启动时不会去调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象
	 * request: 同一次请求创建一个实例
	 * session: 同一次会话创建一个实例
	 * 
	 */
	@Scope("prototype")
	@Bean("person")
	public Person person() {
		System.out.println("给容器中添加Person对象....");
		return new Person(1,"张三",22);
	}
}
  1. 测试类,IOCTest.java
java 复制代码
package com.yuan.annotation.test;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.yuan.annotation.bean.Person;
import com.yuan.annotation.config.MainConfig;
import com.yuan.annotation.config.ScopeConfig;

public class IOCTest {
	private AnnotationConfigApplicationContext applicationContext;

	@Test
	public void test02() {
		applicationContext = new AnnotationConfigApplicationContext(ScopeConfig.class);
		/*
		 * String [] definitionNames = applicationContext.getBeanDefinitionNames();
		 * for(String beanName : definitionNames) { System.out.println(beanName); }
		 */
		  //默认为单实例的 
		  Person person = (Person) applicationContext.getBean("person");
		  Person person2 = (Person) applicationContext.getBean("person");
		  System.out.println(person == person2);
	}
}

1.5 @Lazy注解,bean懒加载注解

java 复制代码
package com.yuan.annotation.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import com.yuan.annotation.bean.Person;

@Configuration
public class LazConfig {
	
	/**
	 * @Lazy:懒加载,针对scope为单实例的bean而言
	 * 单实例bean,默认容器启动的时候创建
	 * 懒加载:容器启动时不创建对象,第一次使用(获取)Bean对象,并初始化
	 * @return
	 */
	@Lazy
	@Bean
	public Person person() {
		return new Person(1,"张三",22);
	}
}

1.6 @Conditional-按照条件注册bean

@Conditional({Condation}) : 按照一定的条件进行判断,满足条件给容器中注册bean

案例:根据操作系统的创始人来实例对应的Person

  1. 需要定义两个Condition类,如LinuxCondition.java和WindowsCondition.java
  • LinuxCondition.java和WindowsCondition.java必须实现Condition接口

  • WindowsCondition.java

java 复制代码
package com.yuan.annotation.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
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;

/**
 * 判断是否为Windows系统
 * @author jinshengyuan
 *
 */
public class WindowsCondition implements Condition{
	/**
	 * ConditionContext : 判断条件能使用的上下文(环境)
	 * AnnotatedTypeMetadata : 注解信息
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		//判断是否Linux系统
		//1.能获取到IOC使用的beanFactory
		ConfigurableListableBeanFactory beanFactory =  context.getBeanFactory();
		
		//2.获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		
		//3.获取当前环境信息
		Environment environment = context.getEnvironment();
		
		//4.获取bean定义的注册类
		BeanDefinitionRegistry registry = context.getRegistry();
		//可以判断容器中的bean注册情况,也可以给容器中注册bean
		boolean beanDefinition = registry.containsBeanDefinition("person");
		
		String property = environment.getProperty("os.name");
		
		//如果property中包含Windows,则返回true
		if(property.contains("Windows")) {
			return true;
		}		
		return false;
	}
}
  • LinuxCondition.java
java 复制代码
package com.yuan.annotation.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
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;

/**
 * 判断是否为Linux系统
 * @author jinshengyuan
 *
 */
public class LinuxCondition implements Condition {
    
	/**
	 * ConditionContext : 判断条件能使用的上下文(环境)
	 * AnnotatedTypeMetadata : 注解信息
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		//判断是否Linux系统
		//1.能获取到IOC使用的beanFactory
		ConfigurableListableBeanFactory beanFactory =  context.getBeanFactory();
		
		//2.获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		
		//3.获取当前环境信息
		Environment environment = context.getEnvironment();
		
		//4.获取bean定义的注册类
		BeanDefinitionRegistry registry = context.getRegistry();
		//可以判断容器中的bean注册情况,也可以给容器中注册bean
		boolean beanDefinition = registry.containsBeanDefinition("person");
		
		String property = environment.getProperty("os.name");
		
		//如果property中包含Linux,则返回true
		if(property.contains("Linux")) {
			return true;
		}
		
		return false;
	}
}
  1. @Conditional注解配置类
java 复制代码
package com.yuan.annotation.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import com.yuan.annotation.bean.Person;
import com.yuan.annotation.condition.LinuxCondition;
import com.yuan.annotation.condition.WindowsCondition;

@Configuration
public class ConditionalConfig {
	
	/**
	 * @Conditional({Condation}) : 按照一定的条件进行判断,满足条件给容器中注册bean
	 * @Conditional可以标注在类上,也可以标注在方法上
	 * 标注在类上:类中组件统一设置,满足当前条件,这个类中配置的所有bean才能生效
	 * 需求:
	 * 如果系统是Windows,给容器中注册("bill")
	 * 如果是Linux系统,给容器中注册("linus")
	 */
    //如果为Windows系统则实例化bill类
	@Conditional({WindowsCondition.class})
	@Bean("bill")
	public Person person() {
		return new Person(1,"Bill Gates",65);
	}
	//如果为Linx系统则实例化linus类
	@Conditional({LinuxCondition.class})
	@Bean("linus")
	public Person person1() {
		return new Person(1,"linus",48);
	}
}
  1. 测试类
java 复制代码
package com.yuan.annotation.test;

import java.util.Map;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import com.yuan.annotation.bean.Person;
import com.yuan.annotation.config.ConditionalConfig;
import com.yuan.annotation.config.MainConfig;
import com.yuan.annotation.config.ScopeConfig;

public class IOCTest {
	private AnnotationConfigApplicationContext applicationContext;
	
	@Test
	public void test03() {
		applicationContext = new AnnotationConfigApplicationContext(ConditionalConfig.class);
		ConfigurableEnvironment environment =  applicationContext.getEnvironment();
		//动态获取环境变量的值:Windows 10
		String osName = environment.getProperty("os.name");
		System.out.println(osName);
		
		//获取已定义的bean
		String [] definitionNames = applicationContext.getBeanDefinitionNames();
		for(String beanName : definitionNames) {
			System.out.println(beanName); 			  
		}
		  
		Map<String, Person> map = applicationContext.getBeansOfType(Person.class);
		System.out.println(map);
	}
}
  1. 输出结果

由于是Windows 10,则只有bill类被实例化

tex 复制代码
Windows 10
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
conditionalConfig
bill
{bill=Person(id=1, name=Bill Gates, age=65)}

2. 给容器中注册组件的方式

2.1 包扫描+组件标注注解

@Controller/@Service/@Repository/@Component)[只适用于自己写的类]

2.2 @Bean

[导入的第三方包里面的组件]

2.3 @Import[快速给容器中导入一个组件]

2.3.1 @Import(要导入到容器中的组件)

容器中就会自动注册这个组件,id默认是全类名(如下面的com.yuan.bean.Color)

  • 定义一个Color.java类
java 复制代码
package com.yuan.bean;

/**
 * color 类
 */
public class Color {
}
  • 在ColorMainConfig.java中使用@Import注解向容器中注入Color类
java 复制代码
package com.yuan.config;

import com.yuan.bean.Color;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 21:59
 * @Description: 使用@Import 注册组件
 */
@Configuration
@Import(Color.class) //注入单个组件
//@Import({Color.class,Red.class}) //注入多个组件
public class ColorMainConfig {
}
  • 单元测试
java 复制代码
package com.yuan.test;

import com.yuan.config.ColorMainConfig;
import com.yuan.config.MainConfig;
import com.yuan.config.MyConfigTwo;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 21:59
 * @Description: 使用@Import 注册组件
 */
public class IOCTest {
    private AnnotationConfigApplicationContext applicationContext;

    /**
     * 使用@Import注解向容器注入组件测试 
     */
    @Test
    public void testImport(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ColorMainConfig.class);
        printBeans(applicationContext);
    }
    /**
     * 打印IOC中注入的所有组件
     * @param applicationContext
     */
    public void printBeans(AnnotationConfigApplicationContext applicationContext ){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}
  • 测试打印结果
tex 复制代码
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
colorMainConfig #自定义配置类bean
com.yuan.bean.Color #注入组件(bean)的全类名

2.3.2 ImportSelector:返回需要导入的组件的全类名数组;

  1. 自定义逻辑返回要导入的组件,需要实现ImportSelector接口,结合@Import注解一起使用
  • 自定义MyImportSelector.java
java 复制代码
package com.yuan.condition;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 22:15
 * @Description: 实现ImportSelector接口来自定义逻辑返回要导入的组件
 */
public class MyImportSelector implements ImportSelector {
    /**
     *
     * @param importingClassMetadata 当前标注@Import注解的类的所有注解信息
     * @return 返回值就是导入容器中的组件的全类名
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //可获取标注@Import注解类的所有注解信息
        System.out.println("importingClassMetadata.getClassName():"+importingClassMetadata.getClassName());
        System.out.println("importingClassMetadata.getAnnotations():"+importingClassMetadata.getAnnotations());

        //return new String[0]; //这里不能返回null,可以返回一个空数组
        return new String[]{"com.yuan.bean.Blue","com.yuan.bean.Yellow"};//导入容器中的组件的全类名
    }
}
  • 配置类
java 复制代码
package com.yuan.config;

import com.yuan.bean.Color;
import com.yuan.condition.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 21:59
 * @Description: 使用@Import 注册组件
 */
@Configuration
@Import({Color.class, MyImportSelector.class})
public class ColorMainConfig {
}
  • IOCTest.java测试结果
tex 复制代码
mportingClassMetadata.getClassName():com.yuan.config.ColorMainConfig
importingClassMetadata.getAnnotations():org.springframework.core.annotation.TypeMappedAnnotations@36b4fe2a
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
colorMainConfig
com.yuan.bean.Color
com.yuan.bean.Blue
com.yuan.bean.Yellow

2.3.3 ImportBeanDefinitionRegistrar:手动注册bean到容器中

通过实现ImportBeanDefinitionRegistrar接口,手动注册bean到容器中,需要结合**@Import注解使用**

  • MyImportBeanDefinitionRegistrar.java
java 复制代码
package com.yuan.condition;

import com.yuan.bean.Student;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 22:48
 * @Description: 通过实现ImportBeanDefinitionRegistrar接口,手动注册bean到容器中
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param importingClassMetadata 当前类的注解信息
     * @param registry BeanDefinition注册类
     * @param importBeanNameGenerator
     */
   /* @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
		//此方法还未理解透
    }*/

    /**
     *
     * @param importingClassMetadata 当前类的注解信息
     * @param registry BeanDefinition注册类,
     *        把所有需要添加到容器中的Bean,用 registry.registerBeanDefinition()手工注册进来
     *
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //registry.registerBeanDefinition();
        boolean red = registry.containsBeanDefinition("com.yuan.bean.Red");
        boolean blue = registry.containsBeanDefinition("com.yuan.bean.Blue");
        //如果存在Red与Blue类,则注册自定义的student类
        if(red && blue){
            //指定bean的定义信息(就是Bean的类型)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Student.class);
            //自定义bean的名字为student
            registry.registerBeanDefinition("student",beanDefinition);
        }
    }
}
  • 配置类ColorMainConfig.java
java 复制代码
package com.yuan.config;

import com.yuan.bean.Color;
import com.yuan.bean.Red;
import com.yuan.condition.MyImportBeanDefinitionRegistrar;
import com.yuan.condition.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import javax.swing.text.rtf.RTFEditorKit;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 21:59
 * @Description: 使用@Import 注册组件
 */
@Configuration
@Import({Color.class, Red.class,MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class ColorMainConfig {
}
  • 测试结果
tex 复制代码
importingClassMetadata.getClassName():com.yuan.config.ColorMainConfig
importingClassMetadata.getAnnotations():org.springframework.core.annotation.TypeMappedAnnotations@574b560f
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
colorMainConfig
com.yuan.bean.Color
com.yuan.bean.Red
com.yuan.bean.Blue
com.yuan.bean.Yellow
student  #手工注册到容器的bean

3.使用Spring提供的 FactoryBean(工厂Bean);

3.1 默认获取到的是工厂bean调用getObject创建的对象

3.2 要获取工厂Bean本身,要获取工厂Bean本身,我们需要给id前面加一个&,如:&colorFactoryBean

  1. 自定义ColorFactorBean.java,实现FactoryBean接口
java 复制代码
package com.yuan.bean;

import org.springframework.beans.factory.FactoryBean;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 23:15
 * @Description: 创建一个Spring定义的FactoryBean
 */
public class ColorFactorBean implements FactoryBean<Color> {
    /**
     * 是单例么?
     * true:是,这个bean在容器中只会保留一份;
     * false: 多实例,每次都会创建一个新的bean
     * @return
     */
    @Override
    public boolean isSingleton() {
        return false;
    }

    /**
     *
     * @return
     * @throws Exception
     */
    @Override
    public Color getObject() throws Exception {
        return new Color();
    }

    /**
     * 返回一个Color对象,这个对象会创建到容器中
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }
}
  1. 主配置类中注册ColorFactorBean
java 复制代码
package com.yuan.config;

import com.yuan.bean.Color;
import com.yuan.bean.ColorFactorBean;
import com.yuan.bean.Red;
import com.yuan.condition.MyImportBeanDefinitionRegistrar;
import com.yuan.condition.MyImportSelector;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import javax.swing.text.rtf.RTFEditorKit;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 21:59
 * @Description: 使用@Import 注册组件
 */
@Configuration
@Import({Color.class, Red.class,MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class ColorMainConfig {

    /**
     * 注入ColorFactorBean对象
     * @return
     */
    @Bean
    public ColorFactorBean colorFactorBean(){
        return new ColorFactorBean();
    }
}
  1. 测试
java 复制代码
package com.yuan.test;

import com.yuan.config.ColorMainConfig;
import com.yuan.config.MainConfig;
import com.yuan.config.MyConfigTwo;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author: Jinsheng·yuan
 * @CreateDate: 2020/1/14 21:59
 * @Description: 使用@Import 注册组件
 */
public class IOCTest {
    private AnnotationConfigApplicationContext applicationContext;

    /**
     * 使用@Import注解向容器注入组件测试
     */
    @Test
    public void testImport(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ColorMainConfig.class);
        Object colorFactorBean = applicationContext.getBean("colorFactorBean");
        Object colorFactorBean1 = applicationContext.getBean("colorFactorBean");
        System.out.println(colorFactorBean == colorFactorBean1); //是否为同意对象
        //1. 获取Bean的类型,默认获取的的是工厂bean调用 getObject()对象创建的bean,如下获取的为:com.yuan.bean.Color
        System.out.println("colorFactorBean的类型:"+colorFactorBean.getClass());
        //2. 若要获取工厂bean本身,则需要给bean的id前面加一个 & ,如&colorFactorBean
        Object factoryBean = applicationContext.getBean("&colorFactorBean");
        System.out.println("colorFactorBean本身的类型:"+factoryBean.getClass());
        printBeans(applicationContext);
    }

    /**
     * 打印IOC中注入的所有组件
     * @param applicationContext
     */
    public void printBeans(AnnotationConfigApplicationContext applicationContext ){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}
  1. 测试结果
tex 复制代码
importingClassMetadata.getClassName():com.yuan.config.ColorMainConfig
importingClassMetadata.getAnnotations():org.springframework.core.annotation.TypeMappedAnnotations@574b560f
false
colorFactorBean的类型:class com.yuan.bean.Color
colorFactorBean本身的类型:class com.yuan.bean.ColorFactorBean
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
colorMainConfig
com.yuan.bean.Color
com.yuan.bean.Red
com.yuan.bean.Blue
com.yuan.bean.Yellow
colorFactorBean
student
相关推荐
Theodore_10224 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
冰帝海岸5 小时前
01-spring security认证笔记
java·笔记·spring
世间万物皆对象5 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
没书读了6 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
小二·6 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
懒洋洋大魔王6 小时前
RocketMQ的使⽤
java·rocketmq·java-rocketmq
武子康6 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神7 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
qq_327342737 小时前
Java实现离线身份证号码OCR识别
java·开发语言