Spring容器核心技术IOC学习
什么是bean?
被Spring管理的对象就是bean,和普通对象的区别就是里面bean对象里面的属性也被注入了。
如何配置bean?
@Component方式、@bean配合配置类的方式、@import导入方式、类实现importSelect的方式
@Component方式
在需要被注册成bean的类上加上这个注解就可以了,只要spring能够扫描到,配置了@Component的类会被注册成bean
@Component的扩展注解还有@Service、@Repository
@bean配合配置类的方式
@bean写在方法上面并且结合配置类
@Configuration
@ComponentScan
public class SpringConfig {
@Bean
public User user(){
return new User();
}
}
特别注意@bean底层会走cglib动态代理进行增强,代理逻辑就是先从spring容器中去找,如果没找到才会创建bean,找到了直接返回,目的是防止多例bean
- 测试类
@org.junit.Test
public void test(){
//要依赖spring注入,就需要从spring容器中获取UserService
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = (User) context.getBean("user");
System.out.println(user);
}
@import导入方式
@import注解导入的类会被spring注册成一个bean,一般这个注解放在配置类上,但是也可以放在其他ben类上
、
@Configuration
@ComponentScan
@Import(User.class)
public class SpringConfig {
}
- 测试
@org.junit.Test
public void test(){
//要依赖spring注入,就需要从spring容器中获取UserService
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = (User) context.getBean(User.class);
System.out.println(user);
}
实现ImportSelector类的方式-批量注册bean
一般配合@import注解使用
@Import(实现ImportSelector.class)
- 实现了ImportSelector的类
重写selectImports方法,返回一个字符串数组,里面的内容就是要注册成bean的类的路径全限定名
可以批量注册bean(通过实现selectImports,返回bean的完整类路径字符串数组)
public class UserImportSelect implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.spring.bean.User"};
}
}
- 配合@import
@Configuration
@ComponentScan
@Import(UserImportSelect.class)
public class SpringConfig {
}
- 测试
@org.junit.Test
public void test(){
//要依赖spring注入,就需要从spring容器中获取UserService
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = (User) context.getBean(User.class);
System.out.println(user);
}
实现ImportBeanDefinitionRegistrar的方式
调用BeanDefinition注册器,手动注册一个bean
一般也是配合@import注解使用
public class UserImportSelect implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
//调用BeanDefinition注册器,手动注册一个bean
RootBeanDefinition beanDefinition=new RootBeanDefinition();
beanDefinition.setBeanClassName("com.spring.bean.User");
registry.registerBeanDefinition("user",beanDefinition);
}
}
- 配合@import注解
@Configuration
@ComponentScan
@Import(UserImportSelect.class)
public class SpringConfig {
}
- 测试
@org.junit.Test
public void test(){
//要依赖spring注入,就需要从spring容器中获取UserService
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = (User) context.getBean(User.class);
System.out.println(user);
}
实例化bean
Spring在实例化bean的时候,当扫描某个类发现有@component或者其他注解的时候,会调用这个类的无参构造函数,从而实例化bean
推断构造函数
规则:
- 默认使用无参构造函数
- 无参构造函数和有参构造函数同时存在,也会默认调用无参构造函数
- 如果只有一个有参构造函数,spring会用有参构造函数,同时会将有参构造函数的参数实例化bean(有的时候会造成循环依赖问题)
- 如果有多个有参构造函数,spring就不知道调用哪个了,必须指定默认的构造函数。指定方法就是方法上添加@Autowired注解,如下所示
@Data
public class User {
private Integer id;
private String name;
private Person person;
private UserService userService;
public User(Person person) {
System.out.println("创建user的构造函数");
this.person = person;
}
//指定默认的构造函数
@Autowired
public User(Person person, UserService userService) {
this.person = person;
this.userService = userService;
}
}
使用实例工厂方法实例化----@Bean的方式
可以自由的选择构造函数进行实例化
使用工厂Bean。实例化-----FactoryBean
-
FactoryBean是一个接口
-
需要有一个Bean,一旦这个Bean实现FactoryBean就成为了特殊的Bean
-
可以自由的选择构造函数进行实例化
特殊 就是根据bean的名字实际上是获取getObject返回的对象(狸猫换太子)
-
实现FactoryBean的方法
@Data
@Component
public class User implements FactoryBean<Person> {
private Integer id;
private String name;
//特殊 就是根据bean的名字实际上是获取getObject返回的对象(狸猫换太子)
public Person getObject() throws Exception {
return new Person();
}
public Class<?> getObjectType() {
return null;
}
}
- 测试
@org.junit.Test
public void test(){
//要依赖spring注入,就需要从spring容器中获取UserService
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
System.out.println(context.getBean("user"));
}
可以看到返回的bean是getobject方法返回实例化bean
依赖注入(DI)
@Autowired
要实现依赖注入一定要使用@Autowired?
1、@Bean方法的参数会自动注入
2、构造函数的参数也会自动注入
- 特性:
- 可以写在方法、构造函数、字段
1、写在构造函数(一般是多个有参构造函数,用@Autowired加在构造函数上来指定默认的构造函数)
2、写在字段:表示依赖注入
3、写在方法:方法里的参数会自动注入 - 先byType后byName