<!-- spring ioc 核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
在Maven resource
目录下创建 META-INF
文件夹,写 spring 的配置文件。
<!-- 配置文件名为 dependency-look-context.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="thinking.in.spring.ioc.overview.domain.User">
<property name="id" value="10"></property>
<property name="name" value="张三"></property>
</bean>
</beans>
根据 Bean
名称查找包括:
配置 Bean:
<!-- 配置 Bean -->
<bean id="user" class="thinking.in.spring.ioc.overview.domain.User">
<property name="id" value="10"></property>
<property name="name" value="张三"></property>
</bean>
<!-- ObjectFactoryCreatingFactoryBean 内部类实现了 ObjectFactory -->
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"></property>
</bean>
从 Ioc 容器中获取 Bean:
public class DependencyLookupDemo {
public static void main(String[] args) {
// 配置 XML 文件
// 启动 Spring Application Context
String configLocation = "classpath:/META-INF/dependency-look-context.xml";
BeanFactory beanFactory = new ClassPathXmlApplicationContext(configLocation);
lookUpInRealTime(beanFactory);
lookUpInLazy(beanFactory);
}
// 1: 延时查找
private static void lookUpInLazy(BeanFactory beanFactory) {
// 并没有实例化我们注入的 bean
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
// 在这里实例化注入的 bean
User user = objectFactory.getObject();
System.out.println("延时查找: " + user);
}
// 2: 实时查找
private static void lookUpInRealTime(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("实时查找: " + user);
}
}
延迟加载:ObjectFactory 对象并不是直接返回了实际的 Bean,而是一个 Bean 的查找代理。当得到 ObjectFactory 对象时,相当于 Bean 没有被创建,只有当 getObject() 方法时,才会触发 Bean 实例化等生命周期。
public class DependencyLookupDemo {
public static void main(String[] args) {
// 配置 XML 文件
// 启动 Spring Application Context
String configLocation = "classpath:/META-INF/dependency-look-context.xml";
BeanFactory beanFactory = new ClassPathXmlApplicationContext(configLocation);
lookupByType(beanFactory);
lookupCollectionByType(beanFactory);
}
// 1: 根据类型查找 Bean, 以集合的方式返回
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("查找到的所有 User 集合对象: " + users);
}
}
// 2: 按照类型查找
private static void lookupByType(BeanFactory beanFactory) {
User user = beanFactory.getBean(User.class);
System.out.println("按照类型查找: " + user);
}
}
根据类型查找Bean,并以集合的方式返回,和 spring-boot 中注入类似:
@Autowired
Map<String, User> users;
自定义注解:
/**
* 自定义注解
*
* @author Ringo
* @date 2021/8/21 23:51
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Super {
}
创建父类:
public class User {
private Long id;
private String name;
// ..get set
}
创建子类:
// 标注上 @Super 注解
@Super
public class SuperUser extends User{
private String address;
// ..get set
}
将 User、SuperUser
加入到 IoC 容器:
注:@Primary
有同样的效果。
<bean id="user" class="thinking.in.spring.ioc.overview.domain.User">
<property name="id" value="10"></property>
<property name="name" value="张三"></property>
</bean>
<bean id="superUser" class="thinking.in.spring.ioc.overview.domain.SuperUser" parent="user" primary="true">
<!-- SuperUser 也是 User, 按照类型找就会报错, Spring 不知道应该找哪个Bean -->
<!-- primary 可以指定 bean 类型, 当 bean 实例冲突时先找这个 bean -->
<property name="address" value="杭州"/>
</bean>
在 IoC 容器中安装注解查找 Bean:
public class DependencyLookupDemo {
public static void main(String[] args) {
// 配置 XML 文件
// 启动 Spring Application Context
String configLocation = "classpath:/META-INF/dependency-look-context.xml";
BeanFactory beanFactory = new ClassPathXmlApplicationContext(configLocation);
// 按注解类型查找bean
lookupByAnnotationType(beanFactory);
}
// 通过注解方式查找
private static void lookupByAnnotationType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory =
(ListableBeanFactory) beanFactory;
Map<String, User> users =
(Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println(users);
}
}
}
创建UserRepository
类,属性为集合。
public class UserRepository {
private Collection<User> users;
// get set...
}
dependency-injection-context.xml
写一个新的配置文件。
注意:新的配置会导入之前的配置 dependency-look-context.xml
。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 注意:通过导入复用 dependency-look-context.xml -->
<import resource="dependency-look-context.xml"/>
<bean id="userRepository" class="thinking.in.spring.ioc.overview.repository.UserRepository"
autowire="byType"> <!-- 2: 自动配置 -->
<!-- 1: 手动配置 -->
<!-- 使用 util:list 标签需要导入对应的 util 名称空间(需要添加以下三个) -->
<!-- xmlns:util="http://www.springframework.org/schema/util" -->
<!-- http://www.springframework.org/schema/util-->
<!-- http://www.springframework.org/schema/util/spring-util-4.0.xsd-->
<!-- <property name="users">-->
<!-- <util:list>-->
<!-- <ref bean="user"/>-->
<!-- <ref bean="superUser"/>-->
<!-- </util:list>-->
<!-- </property>-->
</bean>
</beans>
在IoC容器中查找 UserRepository
的bean。
public class DependencyInjectionDemo {
public static void main(String[] args) {
// 这里使用的是新创建的配置
String configLocation = "classpath:/META-INF/dependency-injection-context.xml";
BeanFactory beanFactory = new ClassPathXmlApplicationContext(configLocation);
lookupInType(beanFactory);
}
private static void lookupInType(BeanFactory beanFactory) {
UserRepository userRepository = beanFactory.getBean(UserRepository.class);
System.out.println(userRepository);
}
}
UserRepository
中的属性为 BeanFactory
:
public class UserRepository {
private BeanFactory beanFactory;
// get set...
}
将 UserRepository
直接加入到容器, 并自动注入:
<bean id="userRepository" class="thinking.in.spring.ioc.overview.repository.UserRepository"
autowire="byType" />
依赖查找 和 依赖注入两种方式查看:
public class DependencyInjectionDemo {
public static void main(String[] args) {
String configLocation = "classpath:/META-INF/dependency-injection-context.xml";
BeanFactory beanFactory = new ClassPathXmlApplicationContext(configLocation);
// 依赖注入
System.out.println(beanFactory.getBean(UserRepository.class).getBeanFactory());
// 依赖查找
// 内建依赖不能通过依赖查找找到
System.out.println(beanFactory.getBean(BeanFactory.class));
}
}
Spring IoC依赖来源:
// 依赖来源一:自定义Bean
UserRepository userRepository = beanFactory.getBean(UserRepository.class);
// 依赖来源二:依赖注入(容器内建依赖) BeanFactory 不是Bean, 不能用依赖查找
// 但是可以用【依赖注入】的方式来获取
System.out.println(userRepository.getBeanFactory());
// 依赖来源三:容器内创建的Bean
Environment environment = beanFactory.getBean(Environment.class);
注意:自定义的bean和内建的bean能够通过依赖查找查询到,但是内建依赖是不能通过依赖查找查询到,因为他们的来源不同。
BeanFactory 并不是 Bean,Java Bean 是一种功能组件,它是 Java对象的方式封装。这里重点是讨论 IoC 依赖的来源,所谓依赖就是被组合的对象。
Bean定义配置:
IoC容器配置:
外部化属性配置:
回顾之前创建的 UserRepository
:
public class UserRepository {
private BeanFactory beanFactory;
// get set...
}
将 UserRepository
加入到容器中,并且配置 autowired
。
<bean id="userRepository" class="thinking.in.spring.ioc.overview.repository.UserRepository"
autowire="byType">
但是为什么等式不成立?
String configLocation = "classpath:/META-INF/dependency-injection-context.xml";
BeanFactory beanFactory = new ClassPathXmlApplicationContext(configLocation);
// 依赖注入
UserRepository userRepository = beanFactory.getBean(UserRepository.class);
// 这个等式为什么不成立?
System.out.println(userRepository.getBeanFactory() == beanFactory);
ApplicationContext
就是 BeanFactory
,只不过子类比父类功能更强大。
实际上,可以用 ApplicationContext
来 代替 BeanFactory
。
String configLocation = "classpath:/META-INF/dependency-injection-context.xml";
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(configLocation);
// 依赖注入
UserRepository userRepository = applicationContext.getBean(UserRepository.class);
System.out.println(applicationContext);
System.out.println(userRepository.getBeanFactory());
// 这个等式为什么不成立?
System.out.println(userRepository.getBeanFactory() == applicationContext);
// 这个等式成立
System.out.println(userRepository.getBeanFactory() == applicationContext.getAutowireCapableBeanFactory());
ApplicationContext
除了 IoC 容器角色, 还提供:
结论:
BeanFactory
是 Spring 底层 IoC 容器。ApplicationContext
是具备应用特性的 BeanFactory
超集。显式声明 DefaultListableBeanFactory
充当 Spring IoC 容器:
// 单纯的使用 BeanFactory 获得 IoC 容器中的 Bean
// 1: 创建 BeanFactory 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2: 加载配置
// 构造器参数是 BeanDefinitionRegistry
// DefaultListableBeanFactory 恰好实现了 BeanDefinitionRegistry
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String location = "classpath:META-INF/dependency-look-context.xml";
// 返回加载 Bean Definitions 的数量
int count = reader.loadBeanDefinitions(location);
System.out.println("加载 Bean Definition 的数量: " + co User.class);
System.out.println("查找到容器中所有 User Bean: " + users);
如果使用 BeanFactory
当做 IoC 容器,就没有事件发布、国际化等特性了!
显示声明 AnnotationConfigurationApplication
来使用 Spring IoC 容器:
/**
* 注解的 {@link ApplicationContext} 作为 IoC 容器示例
*
* @author Ringo
* @date 2021/8/22 21:23
*/
public class AnnotationApplicationContextAsIocContainerDemo {
public static void main(String[] args) {
// 1: 创建 ApplicationContext 作为 IoC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 2: 将当前类注册为 Configuration 类
applicationContext.register(AnnotationApplicationContextAsIocContainerDemo.class);
// 3: 调用 refresh() 启动应用上下文(必须调用)
applicationContext.refresh();
// 4: IoC 容器中找 Bean
Map<String, User> users = applicationContext.getBeansOfType(User.class);
System.out.println("IoC 容器中查找到的User Bean: " + users);
}
/**
* 通过 Java 注解的方式定义 Bean
*/
@Bean
public User user() {
User user = new User();
user.setId(10L);
user.setName("zs");
return user;
}
}
Spring 框架实现了控制反转原则(IoC)。IoC 包括【依赖查找】和【依赖注入】。
依赖注入(DI):可以通过属性、构造器、Set方法区注入依赖。IoC 容器会把注入的依赖放到创建的Bean中。
BeanFactory
是 IoC 的底层容器。
FactoryBean
是创建 Bean 的一种方式,帮助实现复杂的初始化逻辑。
IoC 配置元信息读取和解析、IoC 容器生命周期、Spring 事件发布、国际化等。
属性(Property) | 说明 |
---|---|
Class | Bean全类目,必须是具体类,不能用抽象类或者接口。 |
Name | Bean的名称或者ID。 |
Scope | Bean的作用域(singleton、prototype等)。 |
Constructor arguments | Bean构造器参数(用于依赖注入)。 |
Properties | Bean属性设置(用于依赖注入)。 |
Autowiring mode | Bean自动绑定模式(如:通过名称 byName)。 |
Lazy initialization mode | Bean延迟初始化模式(延迟和非延迟)。 |
Initialization method | Bean初始化回调方法名称。 |
Destruction method | Bean销毁回调方法名称。 |
// 1: 通过 BeanDefinitionBuilder 构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 通过属性设置
beanDefinitionBuilder
.addPropertyValue("id", 10)
.addPropertyValue("name", "张三");
// 获取 BeanDefinition 实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// BeanDefinition 并非 Bean 最终状态, 可以自定义修改
// 2. 通过 AbstractBeanDefinition 以及派生类
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
// 设置 Bean 类型
genericBeanDefinition.setBeanClass(User.class);
// 通过 MutablePropertyValues 批量操作属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
// propertyValues.addPropertyValue("id", "80");
// propertyValues.addPropertyValue("name", "李四");
// 和上面 addPropertyValue() 方法效果一样
propertyValues
.add("id", "80")
.add("name", "李四");
// 通过 set MutablePropertyValues 批量操作属性
genericBeanDefinition.setPropertyValues(propertyValues);
Bean 别名(Alias)的价值:
配置 Bean 的信息和别名:
<!-- 创建Bean 加入到 IoC 容器 -->
<bean id="user" class="thinking.in.spring.ioc.overview.domain.User" scope="singleton">
<property name="id" value="10"/>
<property name="name" value="张三"/>
</bean>
<!-- 将 IoC 容器中 "User Bean" 关联/建立 别名 -->
<alias name="user" alias="ringo-user"/>
IoC 容器中根据 Alias 查找 Bean:
// 1: 创建 IoC 容器 加载配置元信息
String configLocation = "classpath:META-INFO/bean-definitions-context.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configLocation);
// 2: 依赖查找
// 通过 Bean Name 查找
User user = (User) applicationContext.getBean("user");
// 通过 Bean Alias 查找
User ringo = (User) applicationContext.getBean("ringo-user");
System.out.println("user: " + user);
System.out.println("ringo: " + ringo);
System.out.println("user == ringo ? " + (user == ringo)); // true
BeanDefinition注册到IoC容器:
<bean name="" .. />
。BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)
。BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition, BeanDefinitionRegistry)
。AnnotatedBeanDefinitionReader#Register(Class...)
。注意:Java API 的【配置方式】实现是 AnnotationConfigApplicationContext
的 registter(Class...)
方法。
/**
* 注解 {@link org.springframework.beans.factory.config.BeanDefinition} 示例
*
* @author Ringo
* @date 2021/8/23 23:19
*/
// 3: 通过 @Import 来进行导入
// @Import 配合 @Configuration 一起使用, 将标记的类加入到 IoC 容器
@Import(AnnotationBeanDefinitionDemo.Config.class)
@Configuration
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
// 创建 IoC 容器
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类)
// 等同于在 Config 类上添加 @Configuration 注解
// applicationContext.register(AnnotationBeanDefinitionDemo.class);
// 这里使用包扫描
applicationContext.scan("com.ymy.thinking.in.spring.bean.definition.**");
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找
Map<String, Config> configBeans =
applicationContext.getBeansOfType(Config.class);
Map<String, User> userBeans = applicationContext.getBeansOfType(User.class);
System.out.println("Config 类型所有的 Beans :" + configBeans);
System.out.println("User 类型所有的 Beans :" + userBeans);
// 显示关闭 Spring 应用上下文
applicationContext.close();
}
// 2. 通过 @Component 方式定义 Bean
// 使用了 @Import 方式, 就不使用 @Component 了(两种方式 任选其一)
// @Component
public static class Config {
// 1: 通过 @Bean 的方式定义 Bean
/**
* 通过 Java 注解的方式, 定义了一个 Bean.
* 配置 Bean 的别名.
*/
@Bean(name = {"user", "ringo-user"})
public User user() {
User user = new User();
user.setId(8848L);
user.setName("李四");
return user;
}
}
}
/**
* Java API 注册 {@link org.springframework.beans.factory.config.BeanDefinition} 到 IoC 容器
*
* @author Ringo
* @date 2021/8/24 22:22
*/
public class JavaAPIRegistryBeanDefinitionDemo {
public static void main(String[] args) {
// 创建 IoC 容器
// AnnotationConfigApplicationContext 实现了 BeanDefinitionRegistry接口
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
// 包扫描
applicationContext.scan("com.ymy.thinking.in.spring.bean.definition.**");
// 命名注册
registerBeanDefinition(applicationContext, "zs-user");
// 非命名注册
registerBeanDefinition(applicationContext);
// 开启 Spring 应用上下文
applicationContext.refresh();
// 依赖查找
Map<String, User> users = applicationContext.getBeansOfType(User.class);
System.out.println("IoC 容器中所有 User 类型的 Bean: ");
users.forEach((k, v) -> System.out.println(k + "=" + v));
// 关闭 Spring 应用上下文
applicationContext.close();
}
// 命名方式 注册
public static void registerBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(User.class)
.addPropertyValue("id", 3500L)
.addPropertyValue("name", "张三");
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
if (StringUtils.hasText(beanName)) {
// 命名注册
registry.registerBeanDefinition(beanName, beanDefinition);
} else {
// 非命名注册
BeanDefinitionReaderUtils
.registerWithGeneratedName(beanDefinition, registry);
}
}
// 非命名方式 注册
public static void registerBeanDefinition(BeanDefinitionRegistry registry) {
registerBeanDefinition(registry, null);
}
// 配置方式 注册
@Configuration
public static class Config {
@Bean(name = "lisi-user")
public User user() {
User user = new User();
user.setName("里斯");
user.setId(89L);
return user;
}
}
}
输出结果:
Bean实例化(Instantiation):
常规方式
FactoryBean
(配置元信息:XML、Java 注解 和 Java API)。特殊方式:
ServiceLoaderFactoryBean
(配置元信息、XML、Java 注解 和 Java API)。AutowireCapableBeanFactory#createBean(Class, boolean)
。BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)
。创建 Person 类,声明一个静态方法,用于创建对象。
public class Person {
private String name;
private Integer age;
public static Person create() {
Person person = new Person();
person.setName("Ringo");
person.setAge(18);
return person;
}
// get set...
}
在 XML 配置元信息中声明。
<!-- static method 实例化Bean -->
<bean id="person-by-static-method"
class="com.ymy.thinking.in.spring.bean.entity.Person"
factory-method="create"/>
创建 PersonFactory 和默认的实现类。
public interface PersonFactory {
default Person create() {
return Person.create();
}
}
// 默认实现类
public class DefaultPersonFactory implements PersonFactory {
}
在 XML 配置元信息中声明。
<!-- 实例 method 实例化Bean -->
<bean id="personFactory"
class="com.ymy.thinking.in.spring.bean.factory.DefaultPersonFactory"/>
<bean id="person-by-instance-method"
class="com.ymy.thinking.in.spring.bean.entity.Person"
factory-bean="personFactory" factory-method="create"/>
创建 PersonFactoryBean 实现 FactoryBean
接口。
public class PersonFactoryBean implements FactoryBean<Person> {
@Override
public Person getObject() throws Exception {
return Person.create();
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
}
在 XML 配置元信息中声明。
<!-- FactoryBean 实例化 Bean -->
<bean id="person-by-factory-bean"
class="com.ymy.thinking.in.spring.bean.entity.PersonFactoryBean"/>
// 1: 创建 IoC 容器
String configLocation = "classpath:META-INFO/bean-instance-context.xml";
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(configLocation);
// 2: 依赖查找
// 静态方法 实例化Bean
Person personByStaticMethod =
applicationContext.getBean("person-by-static-method", Person.class);
// 实例方法 实例化Bean
Person personByInstanceMethod =
applicationContext.getBean("person-by-instance-method", Person.class);
// FactoryBean 实例化Bean
// 注意:这里类型是写 Person.class
Person personByFactoryBean =
applicationContext.getBean("person-by-factory-bean", Person.class);
System.out.println(personByStaticMethod);
System.out.println(personByInstanceMethod);
System.out.println(personByFactoryBean);
System.out.println(personByStaticMethod == personByInstanceMethod); // false
System.out.println(personByStaticMethod == personByFactoryBean); // false
Java 提供了 ServiceLoader
来加载 接口 和 实现类。
ServiceLoader
源码中设置了路径:
private static final String PREFIX = "META-INF/services/";
所以在 classpath 下创建这个路径:
使用 ServiceLoader
来加载 实现类:
// 加载 接口 和 实现类
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ServiceLoader<PersonFactory> serviceLoader =
ServiceLoader.load(PersonFactory.class, classLoader);
// 迭代输出实现类
// 定义多个相同的实现类会自动去重
// 有多个不同的实现类会逐一输出
Iterator<PersonFactory> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
注意:
输出结果,如下所示:
com.ymy.thinking.in.spring.bean.factory.DefaultPersonFactory@7ea987ac
PersonFactory
有多个实现类。
ServiceLoaderFactoryBean
在 XML 配置元信息。
<bean id="personFactoryServiceLoader"
class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
<property name="serviceType"
value="com.ymy.thinking.in.spring.bean.factory.PersonFactory"/>
</bean>
ServiceLoaderFactoryBean
既然是 FactoryBean就有 FactoryBean 的特性。
根据源码可知,从 Ioc 容器获取到 ServiceLoaderFactoryBean
,拿到的结果是 ServiceLoader
!
public class ServiceLoaderFactoryBean
extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {
@Override
protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
return serviceLoader;
}
@Override
public Class<?> getObjectType() {
return ServiceLoader.class;
}
}
测试代码示例:
public class BeanSpecialInstanceDemo {
public static void main(String[] args) {
// 创建 IoC 容器
String configLocation =
"classpath:META-INF/special-bean-instance-context.xml";
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(configLocation);
// 依赖查找
// 注意:这里 getBean 要写 ServiceLoader.class
ServiceLoader<PersonFactory> serviceLoader =
applicationContext.getBean("personFactoryServiceLoader",
ServiceLoader.class);
System.out.println("== Java ServiceLoader ==");
display(serviceLoader);
System.out.println("== Spring ServiceLoaderFactoryBean ==");
serviceLoaderDemo();
}
public static void serviceLoaderDemo() {
// 加载 接口 和 实现类
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ServiceLoader<PersonFactory> serviceLoader =
ServiceLoader.load(PersonFactory.class, classLoader);
display(serviceLoader);
}
public static void display(ServiceLoader<PersonFactory> serviceLoader) {
// 迭代输出实现类
// 定义多个相同的实现类会自动去重
Iterator<PersonFactory> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
输出结果:
Bean 初始化(Initialization)
@PostConstruct
标注方法(Java 提供)。InitializationBean
接口。<bean init-method="init" .../>
。@Bean(initMethod="init")
。AbstractBeanDefinition#setInitMethodName(String)
。PersonFactory
的默认实现类 DefaultPersonFactory
。
以下是三种实现方法:
public class DefaultPersonFactory implements PersonFactory, InitializingBean {
// 1: 基于 @PostConstructor 注解(Java提供)
// 注意:该方法不能有参数
@PostConstruct
public void init() {
System.out.println("@PostConstruct 初始化Bean: PersonFactory init...");
}
// 2: 自定义初始化方法
// 这个方法不常用
public void initPersonFactory() {
System.out.println("自定义初始化方法: PersonFactory init...");
}
// 3: afterPropertiesSet 初始化
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet 初始化方法: PersonFactory init...");
}
}
编写测试用例:
/**
* Bean 初始化示例
*
* @author Ringo
* @date 2021/8/26 22:41
*/
// IoC 容器会扫描到这个类
@Configuration
public class BeanInitializationDemo {
public static void main(String[] args) {
// 创建 IoC 容器
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
// 设置包扫描
applicationContext.scan("com.ymy.thinking.in.spring.bean.initialization.**");
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找
PersonFactory personFactory = applicationContext.getBean(PersonFactory.class);
// 关闭 Spring 应用上下文
applicationContext.close();
}
@Bean(initMethod = "initPersonFactory")
public PersonFactory personFactory() {
return new DefaultPersonFactory();
}
}
运行结果:
Bean 延迟初始化(Lazy Initialization)
<bean lazy-init="true" />
。@Lazy
。思考:当某个 Bean 定义为延迟初始化,那么,Spring 容器返回的对象与非延迟的对象存在怎样的差异?
非延迟加载是在 Spring Application Context 初始化完成之前,就将 Bean 加载到 IoC 容器。
延迟加载是 Spring Application Context 初始化完成之后,由于依赖查找或者依赖注入,触发 Bean 的加载。
@Lazy
注解要配合 @Componet、@Bean
等注解使用,详情看 @Lazy 注解的说明即可。
Bean 销毁(Destroy)
@PreDestroy
标注方法(Java 提供)。DisposableBean
接口的 destroy() 方法。<bean destroy="destroy".../>
。@Bean(destroy="destroyMethod")
。AbstractBeanDefinition#setDestroyMethodName(String)
。写法参考 Bean 的初始化。
三种方法的顺序:
// 关闭 Spring 应用上下文才会触发 Bean 销毁的操作!
applicationContext.close();
Bean 垃圾回收(GC)
finalize()
方法被回调。创建 PersonFactory
实现类。
public class RewriteFinalizePersonFactory implements PersonFactory, DisposableBean {
@Override
protected void finalize() throws Throwable {
System.out.println("当前对象 RewriteFinalizePersonFactory 正在被回收...");
}
@Override
public void destroy() throws Exception {
System.out.println("当前对象 RewriteFinalizePersonFactory 正在被销毁...");
}
}
测试程序:
/**
* Bean 垃圾回收(GC)示例
*
* @author Ringo
* @date 2021/8/27 22:52
*/
public class BeanGarbageCollectionDemo {
public static void main(String[] args) throws IOException {
// 创建 IoC 容器
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
// 注册 Bean. BeanGarbageCollectionDemo 相当于加了 @Configuration 注解
applicationContext.register(BeanGarbageCollectionDemo.class);
// 开启 Spring 应用上下文
applicationContext.refresh();
// 关闭 Spring 应用上下文
applicationContext.close();
// 强制触发 GC
System.gc();
// 阻塞程序, 防止 gc 还没完成程序就结束了!
System.in.read();
@Bean
public PersonFactory personFactory() {
return new RewriteFinalizePersonFactory();
}
}
输出结果:
通过 BeanDefinition 和 外部单体对象 来注册。
注册 外部单体对象 ?
// 创建 IoC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 创建一个外部 PersonFactory 对象
PersonFactory personFactory = new DefaultPersonFactory();
SingletonBeanRegistry beanFactory = applicationContext.getBeanFactory();
// 注册外部单例对象
beanFactory.registerSingleton("personFactory", personFactory);
// 开启 Spring Application Context
applicationContext.refresh();
// 依赖查找
PersonFactory externalRegistryBean = applicationContext.getBean(PersonFactory.class);
PersonFactory lookUpBean = applicationContext.getBean(PersonFactory.class);
System.out.println(externalRegistryBean);
System.out.println(lookUpBean);
// 结果是 true
System.out.println("externalRegistryBean == lookUpBean? " + (externalRegistryBean == lookUpBean));
// 关闭 Spring Application Context
applicationContext.close();
输出结果:
回顾 "定义 Spring Bean" 和 "BeanDefinition 元信息" 。
BeanbDefition
接口表示的是关于 Bean 的定义的元信息,允许我们以 Get/Set 的方式来修改 Bean 定义元信息。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 作用域:单例还是原型
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
void setScope(@Nullable String scope);
String getScope();
// 设置当前 bean 定义的父级 bean 的名称(如果有)。
void setParentName(@Nullable String parentName);
String getParentName();
// 是否是懒加载
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// @Primary
// 多个同类型Bean的时候, 注入优先级
void setPrimary(boolean primary);
boolean isPrimary();
// ...
}
单一类型依赖查找接口 — BeanFactory
getBean(String)
。getBean(String, Object...)
。(尽量不用!)getBean(Class)
。getBean(Class, Object...)
。(尽量不用!)getBeanProvider(Class)
。getBeanProvider(ResolvableType)
。getBean(String, Class)
。// BeanFactory 延迟查找
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
// ObjectProvider 继承自 ObjectFactory
public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
// ... 省略方法
}
getBeanProvider(Class)
的基本使用:
/**
* {@link ObjectProvider} 延迟依赖查找示例
*
* @author Ringo
* @date 2021/8/31 11:31
*/
public class ObjectProviderDemo {
public static void main(String[] args) {
// 创建 IoC 容器
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
// 包扫描
applicationContext.scan("com.ymy.thinking.in.spring.dependency.lookup.**");
// 开启 Spring 应用上下文
applicationContext.refresh();
// 通过 ObjectProvider 实现延迟依赖查找
lookupByObjectProvider(applicationContext, String.class);
// 关闭 Spring 应用上下文
applicationContext.close();
}
private static <T> void lookupByObjectProvider(BeanFactory beanFactory,
Class<T> requiredType) {
ObjectProvider<T> objectProvider = beanFactory.getBeanProvider(requiredType);
// 该方法来自于 ObjectFactory#getObject() 方法
// ObjectFactory 接口可以实现 延迟依赖查找
T object = objectProvider.getObject();
System.out.println(object);
}
/**
* 配置类, 配合包扫描就能解析这个注解
*/
@Configuration
public static class Config {
@Bean
public String hello() {
return "Hello World";
}
}
}
集合类型依赖查找接口 — ListableBeanFactory
getBeanNamesForType(Class)
。getBeanNamesForType(ResolvableType)
。getBeansOfType(Class)
以及重载方法。getBeanNamesForAnnotation(Class<? extends Annotation>)
。getBeansWithAnnotation(Class<? extends Annotation>)
。findAnnotationOnBean(String, Class<? extends Annotation>)
。该方法会返回 Bean 上标注的注解。创建自定义注解:
// RUNTIME 保证在运行时可以被反射到
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface Fine {
}
集合查找 Bean 示例:
public class DependencyLookupByCollectionTypeDemo {
public static void main(String[] args) {
// 创建 IoC 容器
// ApplicationContext 已经实现了 ListableBeanFactory
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
applicationContext.scan("com.ymy.thinking.in.spring.dependency.lookup.**");
// 开启 Spring 应用上下文
applicationContext.refresh();
// 1: 获取同类型 Bean 名称列表
String[] beanNamesForType =
applicationContext.getBeanNamesForType(String.class);
System.out.println("获取同类型Bean名称列表: " +
Arrays.toString(beanNamesForType));
// 2: 获取同类型 Bean 实例列表
Map<String, String> beansOfTypeMap =
applicationContext.getBeansOfType(String.class);
System.out.println("获取同类型 Bean 实例列表: " + beansOfTypeMap);
// 3: 获得标注注解类型 Bean 名称列表
String[] beanNamesForAnnotation =
applicationContext.getBeanNamesForAnnotation(Fine.class);
System.out.println("获得标注注解类型 Bean 名称列表: " +
Arrays.toString(beanNamesForAnnotation));
// 4: 获得标注注解类型 Bean 实例列表
Map<String, Object> beansWithAnnotation =
applicationContext.getBeansWithAnnotation(Fine.class);
System.out.println("获得标注注解类型 Bean 实例列表: ");
beansWithAnnotation.forEach((k, v) -> System.out.println(k + "=" + v));
// 关闭 Spring 应用上下文
applicationContext.close();
}
@Fine
@Configuration
public static class Config {
@Fine
@Bean
public String hello() {
return "hello";
}
@Fine
@Bean
public String world() {
return "world";
}
}
}
集合类型的 Bean 依赖查找结果:
层次性依赖查找接口 — HierarchicalBeanFactory
BeanFactory getParentBeanFactory()
。containsLocalBean
方法实现。(该方法只会查找当前 IoC 容器中的 Bean,不会查询父级 BeanFactory 中的 Bean)。BeanFactoryUtils#beanOfTypeIncludingAncestors
。BeanFactoryUtils#beansOfTypeIncludingAncestors
。BeanFactoryUtils#beanNamesForTypeIncludingAncestors
。创建 parent BeanFactory:
<!-- hierarchical-dependency-lookup-context.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置元信息 -->
<bean id="hello" class="java.lang.String">
<constructor-arg name="original" value="hello parent BeanFactory"/>
</bean>
</beans>
测试案例:
/**
* {@link HierarchicalBeanFactory} 层次性依赖查找 Bean 示例
*
* @author Ringo
* @date 2021/8/31 16:50
*/
public class HierarchicalDependencyLookupDemo {
public static void main(String[] args) {
// 创建 IoC 容器
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
// 注册为 Bean
applicationContext.register(HierarchicalDependencyLookupDemo.class);
// 1: 获取 HierarchicalBeanFactory
// ConfigurableListableBeanFactory 继承了 HierarchicalBeanFactory
ConfigurableListableBeanFactory beanFactory =
applicationContext.getBeanFactory();
// 这里返回 null
System.out.println("当前 BeanFactory 的 Parent BeanFactory:" +
beanFactory.getParentBeanFactory());
// 2. 设置 Parent BeanFactory
HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
beanFactory.setParentBeanFactory(parentBeanFactory);
System.out.println("当前 BeanFactory 的 Parent BeanFactory:" +
beanFactory.getParentBeanFactory());
// 开启 Spring 应用上下文
applicationContext.refresh();
// 查看当前 BeanFactory 是否包含 hello 这个 Bean
displayContainsLocalBean(beanFactory, "hello"); // false
displayContainsLocalBean(parentBeanFactory, "hello"); // true
// 先查子容器 再查父容器
displayContainsBean(beanFactory, "hello"); // true
displayContainsBean(parentBeanFactory, "hello"); // true
// 关闭 Spring 应用上下文
applicationContext.close();
}
// 既查当前 BeanFactory 又查父级 BeanFactory
private static void displayContainsBean(HierarchicalBeanFactory beanFactory,
String beanName) {
System.out.println(containsBean(beanFactory, beanName));
}
// 递归查询(我们自己写的 containsBean的实现)
public static boolean containsBean(HierarchicalBeanFactory beanFactory,
String beanName) {
// 拿到父级的 IoC 容器
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
// 父级 IoC 容器是 HierarchicalBeanFactory
if (parentBeanFactory instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory parentHierarchicalBeanFactory =
(HierarchicalBeanFactory) parentBeanFactory;
if (containsBean(parentHierarchicalBeanFactory, beanName)) {
return true;
}
}
// 父级 IoC 容器不是 HierarchicalBeanFactory, 就只查询当前容器
// containsLocalBean 只返回当前 IoC 容器中的 Bean
// 不会去查询父级的 IoC 容器
return beanFactory.containsLocalBean(beanName);
}
// 只查本地 BeanFactory
private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory,
String beanName) {
System.out.println(beanFactory.containsLocalBean(beanName));
}
/**
* 创建父级 {@link BeanFactory}
*/
private static HierarchicalBeanFactory createParentBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String location =
"classpath:META-INF/hierarchical-dependency-lookup-context.xml";
reader.loadBeanDefinitions(location);
return beanFactory;
}
}
Bean 延迟依赖查找接口:
org.springframework.beans.factory.ObjectFactory
。org.springframework.beans.factory.ObjectProvider
。
getIfAvailable(Supplier)
。ifAvailable(Consumer)
。stream()
。ObjectProvider接口API:
// ObjectProvider 接口
// 1: 容器中有 Bean 就获取, 没有就返回 null。
@Nullable
T getIfAvailable() throws BeansException;
// 2: 容器中有 Bean 就获取, 没有就返回指定对象。
default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
T dependency = getIfAvailable();
return (dependency != null ? dependency : defaultSupplier.get());
}
ObjectProvider接口的使用:
public class ObjectProviderIfAvailableDemo {
public static void main(String[] args) {
// 创建 IoC 容器
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
// 注册当前类到 IoC 容器
applicationContext.register(ObjectProviderIfAvailableDemo.class);
// 开启 Spring 应用上下文
applicationContext.refresh();
// 依赖查找
lookupIfAvailable(applicationContext);
System.out.println("=======================");
lookupByStream(applicationContext);
// 关闭 Spring 应用上lose();
}
// Stream 流式查找
private static void lookupByStream(ApplicationContext applicationContext) {
ObjectProvider<String> objectProvider =
applicationContext.getBeanProvider(String.class);
// Stream 方式
objectProvider.stream().forEach(System.out::println);
// 迭代器方式
objectProvider.iterator().forEachRemaining(System.out::println);
}
// IfAvailable 的方式查找
private static void lookupIfAvailable(ApplicationContext applicationContext) {
ObjectProvider<String> objectProvider =
applicationContext.getBeanProvider(String.class);
// 如果容器中有 Bean 就获取, 没有就返回 null
String beanIfAvailable = objectProvider.getIfAvailable();
// 如果容器中有 Bean 就获取, 没有就返回指定的值
String ifAvailable = objectProvider.getIfAvailable(() -> "aabb");
System.out.println(beanIfAvailable);
System.out.println(ifAvailable);
}
@Bean
@Primary
public String fine() {
return "fine";
}
@Bean
public String message() {
return "message";
}
}
输出结果:
依赖查找安全性对比:
依赖查找类型 | 代表实现 | 是否安全 |
---|---|---|
单一类型查找 | BeanFactory#getBean | 否 |
ObjectFactory#getObject | 否 | |
ObjectProvider#getIfAvailable | 是 | |
集合类型查找 | ListableBeanFactory#getBeansOfType | 是 |
ObjectProvider#stream | 是 |
注意:层次性依赖查找的安全性取决于其扩展的单一或集合类型的 BeanFactory 接口。
AbstractApplicationContext
内建可查找的依赖。
Bean名称 | Bean实例 | 使用场景 |
---|---|---|
environment | Environment 对象 | 外部化配置以及 Profiles |
systemProperties | java.util.Properties 对象 | Java 系统属性 |
systemEnvironment | java.util.map 对象 | 操作系统环境变量 |
messageSource | MessageSource 对象 | 国际化文案 |
lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器 |
applicationEventMulticaster | ApplicationEventMulticaster 对象 | Spring 事件广播器 |
异常类型 | 触发条件(举例) | 场景举例 |
---|---|---|
NoSuchBeanDefinitionException | 当查找的 Bean 不存在于 IoC 容器时 | BeanFactory#getBean() ObjectFactory#getObject() |
NoUniqueBeanDefinitionException | 按类型依赖查找时,IoC 容器中存在多个 Bean 的实例 | BeanFactory#getBean(Class) |
BeanInstantiationException | 当 Bean 所对应的类型非具体类时 | BeanFactory#getBean() |
BeanCreationException | 当 Bean 初始化过程中 | Bean 初始化方法执行异常 |
BeanDefinitionStoreException | 当 BeanDefition 配置元信息非法时 | XML 配置资源无法打开时 |
ObjectFactory、BeanFactory
都提供依赖查找的能力。
不过 ObjectFactory
仅仅关注一个或者一种类型的 Bean 依赖查找,并且自身不具备依赖查找的能力,能力则由 BeanFactory 输出。
BeanFactory
和其字类则提供了单一类型、集合类型以及层次性等多种依赖查找方式。
线程安全(原因不清楚...)
手动模式 — 配置或者编程的方式,提前安排注入规则
自动模式 — 实现方提供依赖自动关联的方式,按照内建的注入规则
手动模式:
自动模式:
下面举一个 Java 注解注入的例子:
/**
* 基于 Java 注解的依赖注入
*
* @author Ringo
* @date 2021/9/29 0:29
*/
public class AnnotationDependencySetterInjectionDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationDependencySetterInjectionDemo.class);
System.out.println(applicationContext.getBean(UserHolder.class));
}
@Bean
public User user() {
User user = new User();
user.setName("李白");
user.setAge(19);
return user;
}
@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
}
手动模式:
自动模式:
构造器注入:
@Controller
public class FooController {
private final FooService fooService;
@Autowired
public FooController(FooService fooService) {
this.fooService = fooService;
}
//使用方式上同,略
}
如果使用构造器注入,在spring项目启动的时候,就会抛出:BeanCurrentlyInCreationException:Requested bean is currently in creation: Is there an unresolvable circular reference?从而提醒你避免循环依赖,如果是field注入的话,启动的时候不会报错,在使用那个bean的时候才会报错。
使用构造器注入的好处:
手动模式:Java注解配置元信息
注意:@Autowired
会忽略静态字段。
@Component
public class Test {
// @Autowired 主要处理实例字段
// @Autowired 会忽略静态字段,无法自动注入。
@Autowired
private static User user;
}
/**
* {@link Autowired} {@link Resource} 基于方法的依赖注入
*
* @author Ringo
* @date 2021/9/30 12:03
*/
public class AnnotationDependencyMethodInjectionDemo {
private UserHolder userHolder;
private UserHolder userHolder2;
// =============================================================
// @Autowired @Resource @Bean 都可以实现方法注入
@Autowired
public void init1(UserHolder userHolder) {
this.userHolder = userHolder;
}
@Resource
public void init2(UserHolder userHolder) {
this.userHolder2 = userHolder;
}
@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
// =============================================================
@Bean
public User user() {
return new User("zsf", 18);
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AnnotationDependencyMethodInjectionDemo.class);
AnnotationDependencyMethodInjectionDemo demo =
applicationContext.getBean(AnnotationDependencyMethodInjectionDemo.class);
System.out.println(demo.userHolder);
System.out.println(demo.userHolder2);
System.out.println(demo.userHolder == demo.userHolder2); // true
}
}
/**
* 基于 {@link Aware} 接口回调的依赖注入示例
*
* @author Ringo
* @date 2021/9/30 13:06
*/
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {
private static BeanFactory beanFactory;
private static ApplicationContext applicationContext;
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AwareInterfaceDependencyInjectionDemo.class);
System.out.println(beanFactory == context.getBeanFactory()); // true
System.out.println(applicationContext == context); // true
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;
}
}
@Qualifier
不仅可以用在 Bean 的依赖注入上,还可以用在 Bean 的声明上。
@Qualifier
也可以用在注解上,派生新的注解,是对 @Qualifier
注解的扩展。
有没有 @Qualifier
可以对 Bean 进行分组。
/**
* 用户组注解, 扩展 {@link Qualifier}
*
* @author Ringo
* @date 2021/9/30 14:37
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier // 可以标注在 Annotation 上
public @interface UserGroup {
}
/**
* {@link Qualifier} 限定注入案例
*
* @author Ringo
* @date 2021/9/30 14:13
* @see Qualifier
* @see UserGroup
*/
public class QualifierAnnotationDependencyInjectionDemo {
@Autowired
private User user; // user2 -> @Primary
@Autowired
@Qualifier("user1") // 指定 Bean name
private User namedUser;
// 整体应用上下文存在 4 个 User 类型的 Bean
// user1
// user2
// user3 -> @Qualifier
// user4 -> @Qualifier
@Autowired
private List<User> allUsers; // 注入所有的 User 类型的 Bean
@Autowired
@Qualifier
private List<User> qualifiedUsers; // 4 Beans = user1 + user2 + user3 + user4
@Autowired
@UserGroup
private List<User> groupedUsers; // 2 Bean = user3 + user4
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
applicationContext.register(QualifierAnnotationDependencyInjectionDemo.class);
applicationContext.refresh();
QualifierAnnotationDependencyInjectionDemo demo =
applicationContext.getBean(QualifierAnnotationDependencyInjectionDemo.class);
System.out.println("demo.user = " + demo.user);
System.out.println("demo.namedUser = " + demo.namedUser);
System.out.println("demo.allUsers = " + demo.allUsers);
System.out.println("demo.qualifiedUsers = " + demo.qualifiedUsers);
System.out.println("demo.groupedUsers = " + demo.groupedUsers);
}
@Bean
@Qualifier
public User user1() {
return new User("zs", 19);
}
@Bean
@Primary
@Qualifier
public User user2() {
return new User("ls", 20);
}
@Bean
@UserGroup // 进行逻辑分组
public User user3() {
return createUser("007");
}
@Bean
@UserGroup // 进行逻辑分组
public User user4() {
return createUser("008");
}
// 工厂方法
public static User createUser(String name) {
User user = new User();
user.setName(name);
return user;
}
}
@Autowired
private User user; // 实时注入
@Autowired
private ObjectProvider<User> userObjectProvider; // 延迟注入
@Autowired
private ObjectFactory<User> userObjectFactory; // ObjectFactory 延迟注入
AutowiredAnnotationBeanPostProcessor
@Autowired
注入过程:
CommonAnnotationBeanPostProcessor
。
注入注解:
生命周期注解:
/**
* 扩展DI的最优方式: 这样实现新旧注解都可以使用
* <p>
* static 静态注入会对 Bean 注入优先级做提升
*/
@Bean
@Order(Ordered.LOWEST_PRECEDENCE - 3)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor beanPostProcessor =
new AutowiredAnnotationBeanPostProcessor();
// 替换原有的注解处理, 使用新注解 @Injected
beanPostProcessor.setAutowiredAnnotationType(Injected.class);
return beanPostProcessor;
}
构造器注入、Setter注入、字段注入、方法注入、接口回调注入。
两种依赖注入的方式都可以用,如果必须依赖的话,那么推荐构造器注入,Setter 注入用于可选依赖。
Spring BeanDefinition:配置元数据
<bean id="user" class="">
。@Bean public class User user() {}
。BeanDefinitionBuilder
。单例对象:API
实现。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。