前言:为了简化开发的步骤和降低设计的耦合性,在spring框架中引入了IOC容器这一概念。IOC理论提出的观点大体是这样的:借助于"第三方"实现具有依赖关系的对象之间的解耦。因此,在spring中,对象的创建与赋值均借助于IOC容器由框架来实现。初始化时,我们将组件放置与IOC容器中儿不具体指定使用该组件的对象,当某一具体对象需要使用组件时,直接从容器中获取即可。
目录:
一、通过@Bean方式添加
通常会通过在配置类中方法上添加@bean将对象注册到容器中。在spring整合其他框架场景中,为了降低模块之间的耦合性,需要考虑使用工厂bean来添加组件1.1 @bean添加组件
示例1:将person实例化并注册到容器中,最后在测试类中从容器中取出person对象。
I) 创建实体类Person.java
package com.allin.pojo;
public class Person {
private String userName;
private Integer age;
private String sex;
public Person(String userName, Integer age, String sex) {
this.userName = userName;
this.age = age;
this.sex = sex;
}
public String getUserName(){
return userName;
}
@Override
public String toString() {
return "Person{" +
"userName='" + userName + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
II) 创建配置类MyConfig,在类上使用@Configuration注解标注为配置类,在类中方法上使用@bean注解将对象注册到容器中。
默认注册到容器中的组件名为注册组件时方法名,可通过@bean(value=“XXX”)修改组件名
package com.allin.config;
import com.allin.pojo.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
@Bean
public Person person(){
return new Person("miaowu",22,"male");
}
}
III) 创建测试类,在测试类中根据组件名将对象从IOC容器中取出
@Test
public void test02(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
String[] definitionNames = applicationContext.getBeanDefinitionNames();
//查询容器中有哪些组件
for(String name : definitionNames){
System.out.println(name);
}
Person person = (Person) applicationContext.getBean("person");
System.out.println(person.getUserName());
}
IV) 测试结果:容器中包含MyConfig和person组件,将person对象按组件名取出并打印person对象中属性值
1.2 使用工厂bean添加组件
当项目中存在多个相同类型实体类,我们不需要将所有实体类实例化并注册到容器中,可以使用工厂bean进行动态选择项目所需要的实体类进行初始化并注册到容器中,以提高项目运行的效率和提高程序设计的灵活性示例2:项目中包含有多种颜色的实体类(Blue,Yellow),选择Blue实体类进行实例化并注册到容器中,测试类将对象取出并进行测试。
I) 创建实体类Blue和Yellow
entity:Blue:
package com.allin.pojo;
public class Blue {
public String description = "this is blue color";
}
entity:Yellow:
package com.allin.pojo;
public class Yellow {
private String discription = "this is yellow color";
}
II) 创建工厂bean类ColorFactoryBean实现FactoryBean,getObject类返回Blue对象
package com.allin.pojo;
import org.springframework.beans.factory.FactoryBean;
public class ColorFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new Blue();
}
@Override
public Class<?> getObjectType() {
return Blue.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
III) 创建配置类MyConfig02注册工厂bean
package com.allin.config;
import com.allin.pojo.ColorFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig02 {
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
IV) 创建测试类
@Test
public void test06(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig02.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String name : beanDefinitionNames){
System.out.println(name);
}
//工厂bean获取的是调用getObject创建的对象
Object bean = applicationContext.getBean("colorFactoryBean");
System.out.println("bean的类型:" + bean.getClass());
Blue bean1 = (Blue) applicationContext.getBean("colorFactoryBean");
System.out.println(bean1.description);
}
v) 测试结果:将colorFactoryBean对象注册入容器中,实际存储在IOC容器中的为以colorFactory为组件名的,由ColorFactory类中getObject()方法实例化的Blue对象
二、通过包扫描方式添加
spring中定义了 @Component、@Service、@Controller、@Repository注释来声明组件,通过在配置类中使用包扫描@ComponentScan将组件添加到容器中示例3:创建实体类User,包含uesrName和password属性,使用@Component注解标注;创建应用类Service,定义add方法,使用@Service标注。在配置类Config01类中将组件注册到容器中,在测试类中将组件从容器中取出进行测试
I) 创建实体类User,使用@Component注解标注
package com.allin.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
@Value("miaowu")
private String userName;
@Value("5201024")
private String password;
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
II) 创建应用类MyService,使用@Service标注注解
package com.allin.service;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void add(){
System.out.println("service……add……execute!");
}
}
III) 创建配置类MyConfig01,使用包扫描将被@Component、@Service注解标注的类注册到容器中。
被标注的类以类名为组件名被注册到容器中
package com.allin.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(value = {"com.allin.pojo", "com.allin.service"})
public class MyConfig01 {
}
IV) 创建测试类,将组件从容器中取出并进行测试
@Test
public void test05(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig01.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String name : beanDefinitionNames){
System.out.println(name);
}
User user = (User)applicationContext.getBean("user");
System.out.println(user);
MyService service = (MyService) applicationContext.getBean("myService");
service.add();
}
V) 测试结果:User、MyService类以类名为组件名注册到容器中
三、通过@Import方式添加
使用@Import方式可以方便注册第三方包到容器中
示例4:将User类通过@Import注册到容器中,User类中包含内容同上示例3
I) 创建实体类User,同上示例3
II) 在配置类Config03上使用@Import导入User类
使用@Import注册的组件名为全类名
package com.allin.config;
import com.allin.pojo.User;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(User.class)
public class MyConfig03 {
}
III) 创建测试类将组件取出
@Test
public void test07(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig03.class);
User bean = (User)applicationContext.getBean("com.allin.pojo.User");
System.out.println(bean);
}
IV) 测试结果:@Import将实体类以全类名为组件名注册到组件中
3.1 ImportSelector接口
ImportSelector接口中含有两个方法:String[] selectImports(AnnotationMetadata importingClassMetadata);
- 返回值:导入到容器中的组件全类名
- AnnotationMetadata:当前标注@Import注解的类的所有注释信息
default Predicate getExclusionFilter();
相当于给selectImports返回的String加一个过滤器,如果Predicate返回为True,则过滤,不进行注册
示例5:将示例2中的Yellow、Blue通过ImportSelector接口导入到容器中,通过getExclusionFilter()过滤掉Blue对象
I) 创建Yellow、Blue对象,同上示例2
II) 实现ImportSelector接口,在selectImports方法将要导入的组件全类名返回,在getExclusionFilter()方法中过滤全类名中含有Blue的组件
package com.allin.importselector;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.function.Predicate;
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com/allin/pojo/Blue","com/allin/pojo/Yellow"};
}
@Override
public Predicate<String> getExclusionFilter() {
return className->className.contains("Blue");
}
}
III) 创建配置类ImportSelectorConfig,将MyImportSelector接口导入
package com.allin.config;
import com.allin.importselector.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Import(MyImportSelector.class)
@Configuration
public class ImportSelectorConfig {
}
IV) 创建测试类,测试容器中包含哪些组件
@Test
public void test08(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ImportSelectorConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String beanName : beanDefinitionNames){
System.out.println("beanName:" + beanName + "===" + "bean对象:" + applicationContext.getBean(beanName));
}
}
V) 测试结果:容器中包含Yellow组件,不含Blue组件
3.2 ImportBeanDefinitionRegistrar接口
ImportBeanDefinitionRegistrar支持我们自己写的代码封装成 BeanDefinition对象;实现此接口的类会回调 postProcessBeanDefinitionRegistry方法注册到spring容器中实例6:將Blue实体类通过ImportBeanDefinitionRegistrar注册到容器中
I) 创建实体类Blue,Bean类中内容同上示例2
II) 创建MyImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口,在registerBeanDefinitions方法中自定义组件名,并将Blue实体类转为组件注册到容器中
package com.allin.registor;
import com.allin.pojo.Blue;
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 MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("red");
if(!definition){
RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);
registry.registerBeanDefinition("Blue",beanDefinition);
}
}
}
III) 创建配置类将ImportBeanDefinitionRegistrar接口导入
package com.allin.config;
import com.allin.registor.MyImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyConfig04 {
}
IV) 创建测试类,查看Blue组件是否注册到容器中
@Test
public void test09(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig04.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String name : beanDefinitionNames){
System.out.println(name);
}
}