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
相关推荐
逊嘘13 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
morris13120 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员1 小时前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU1 小时前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie61 小时前
在IDEA中使用Git
java·git
Elaine2023911 小时前
06 网络编程基础
java·网络
G丶AEOM1 小时前
分布式——BASE理论
java·分布式·八股
落落鱼20131 小时前
tp接口 入口文件 500 错误原因
java·开发语言
想要打 Acm 的小周同学呀1 小时前
LRU缓存算法
java·算法·缓存