依赖注入的模式和类型
模式
手动模式
配置或者编程的方式:
- XML 资源配置元信息(常用)
- Java 注解配置元信息(常用)
- API 配置元信息
自动模式
实现方提供依赖自动关联的方式,按照内建的注入规则:
Autowiring(自动绑定)类型
Setter 方法:<proeprty name= "user" ref= "userBean" />
构造器:<constructor-arg name="user" ref="userBean" />
字段:@Autowired User user;
方法:@Autowired User user;
接口回调:class MyBean implements BeanFactoryAware { ... }
自动绑定(Autowiring)
官方说明
The Spring container can autowire relationships between collaborating beans. You can let Spring resolve collaborators (other beans) automatically for your bean by inspecting the contents of the ApplicationContext.
Spring 容器可以自动关联依赖 Bean 和被依赖 Bean,可以通过检查 ApplicationContext 的内容来让 Spring 自动解析依赖 Bean 的关系。
优点
Autowiring can significantly reduce the need to specify properties or constructor arguments.
自动绑定可以显著减少指定属性或构造器的需要,比如下述代码:
<bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
</bean>
如果我将 value="Steve"
变成到 ref="myName"
这个 Bean,此时 myName 这个 Bean 就会关联到 name 属性上。
如果此时有个名称是 name 的bean,我可以将 <property name="name" value="Steve"/>
注释掉,然后再在<bean id="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User">
添加 autowire="byName
,此时 name 这个 Bean 会被自动装配到 name 属性中。
注意:一般显性绑定比较好,如果某 Bean 的属性字段名称变化,此时按名称找的话,找不到(比如 name -> newName,此时没有名称是 newName 的 Bean。
Autowiring can update a configuration as your objects evolve.
随着对象的更新,自动装配可以自动更新配置(这其实是和 Java 语言特性相关,传引用的类型。)
自动绑定(Autowiring)模式
模式 | 说明 | 备注 |
---|---|---|
no | 默认值,不使用自动绑定,需要手动指定依赖注入对象 | |
byName | 根据被注入属性的名称作为 Bean 名称进行依赖查找, 并将对象设置到该属性。 | |
byType | 根据被注入属性的类型作为依赖类型进行查找, 并将对象设置到该属性。 | 有多个相同 type 的 bean 的情况下,可以使用 @Primary 注解来设置优先级 |
constructor | 特殊 byType 类型, 用于构造器参数 |
具体代码,参照 Autowire
此枚举:
public enum Autowire {
/**
* Constant that indicates no autowiring at all.
*/
NO(AutowireCapableBeanFactory.AUTOWIRE_NO),
/**
* Constant that indicates autowiring bean properties by name.
*/
BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),
/**
* Constant that indicates autowiring bean properties by type.
*/
BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
private final int value;
Autowire(int value) {
this.value = value;
}
public int value() {
return this.value;
}
/**
* Return whether this represents an actual autowiring value.
* @return whether actual autowiring was specified
* (either BY_NAME or BY_TYPE)
*/
public boolean isAutowire() {
return (this == BY_NAME || this == BY_TYPE);
}
}
具体的可以看 AutowireCapableBeanFactory
此类,规定了以下几种:
int AUTOWIRE_NO = 0;
int AUTOWIRE_BY_NAME = 1;
int AUTOWIRE_BY_TYPE = 2;
int AUTOWIRE_CONSTRUCTOR = 3;
@Deprecated
int AUTOWIRE_AUTODETECT = 4;
自动绑定(Autowiring)限制和不足
限制不足
官方文档:
- Explicit dependencies in property and constructor-arg settings always override autowiring. You cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). This limitation is by-design.
- Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is careful to avoid guessing in case of ambiguity that might have unexpected results. The relationships between your Spring-managed objects are no longer documented explicitly.
- Wiring information may not be available to tools that may generate documentation from a Spring container.
Multiple bean definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or Map instances, this is not necessarily a problem. However, for dependencies that expect a single value, this ambiguity is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
个人理解:
- 更准确的
property
和constructor-arg
会覆盖掉自动绑定。不能自动绑定一些简单的属性,比如原生类型、String 类型、Class 类型,这是设计上的限制。咱们自动绑定的时候,会去绑定一个 Bean 或者引用对象,原生类型没法声明成一个 Bean。 - 自动装配不如显式绑定准确。Spring 对于可能产生歧义的产生意料之外结果的猜测要尽量避免(这里可以理解为你绑定属性的时候,对应要绑定 bean 名称写错了。比如你要将一个类的 User 的属性绑定为 SuperUser 这个 bean,但是你手误写成了 User 这个 bean)
- 绑定的相关信息没法在工具中提示,比如从 Spring 容器中生成对应的容器(我理解的是不知道容器里有没有想要绑定的 Bean)
- 如果应用上下文中有多个 bean 的定义,byType 的时候不知道绑定哪个,会抛异常。
对应方案
官方文档:- Abandon autowiring in favor of explicit wiring.
- Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as described in the next section.
- Designate a single bean definition as the primary candidate by setting the primary attribute of its
element to true. - Implement the more fine-grained control available with annotation-based configuration, as described in Annotation-based Container Configuration.—— Limitations and Disadvantages of Autowiring
个人理解:
- 你可以放弃这种方式
- 把
autowire-candidate
改为 false - 有多个相同类型 Bean 的时候,用
@primary
注解标注 -
Setter 方法依赖注入
手动方式
XML 资源配置元信息
- Java 注解配置元信息
- API 配置元信息
相关代码:
XmlDependencySetterInjectionDemo.class
/**
* 基于 xml 资源的依赖 setter 方法注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class XmlDependencySetterInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
String xmlResourcePath = "classpath:/META-INF/dependency-setter-injection.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 依赖查找并创建 Bean
UserHolder userHolder = defaultListableBeanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
dependency-setter-injection.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">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<bean class="com.mindartisan.spring.geek.ioc.dependency.injection.UserHolder">
<!-- 会关联到 id =1,name = Steve 的 bean -->
<property name="user" ref="user"/>
<!-- 同理 -->
<!--<property name="user" ref="superUser"/>-->
</bean>
</beans>
AnnotationDependencySetterInjectionDemo.class
/**
* 基于注解的依赖 setter 方法注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class AnnotationDependencySetterInjectionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类
applicationContext.register(AnnotationDependencySetterInjectionDemo.class);
// 将 User Bean 初始化,供 userHolder(User user) 使用
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
// 关闭 Spring 应用上下文
applicationContext.close();
}
// /**
// * 此处采用的构造器方式
// *
// * @param user 用户
// * @return {@link UserHolder}
// */
@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
/**
* 此处采用 setter 方式
*
* @param user 用户
* @return {@link UserHolder}
*/
// @Bean
// public UserHolder userHolder(User user) {
// UserHolder userHolder = new UserHolder();
// userHolder.setUser(user);
// return userHolder;
// }
}
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="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
</bean>
<bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="北京"/>
</bean>
<!-- 延迟查找使用 -->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
ApiDependencySetterInjectionDemo.class
/**
* 基于 API 实现依赖 setter 方法注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class ApiDependencySetterInjectionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 UserHolder 的 BeanDefinition
BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
// 将 User Bean 初始化
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
// 关闭 Spring 应用上下文
applicationContext.close();
}
/**
* 为 UserHolder 生成 BeanDefinition
*
* @return {@link BeanDefinition}
*/
private static BeanDefinition createUserHolderBeanDefinition() {
// API 用的就是下述代码
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
// 类似 xml 文件中 「ref=""」
beanDefinitionBuilder.addPropertyReference("user", "superUser");
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
return beanDefinition;
}
}
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="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
</bean>
<bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="北京"/>
</bean>
<!-- 延迟查找使用 -->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
自动方式
- byName
- byType
相关代码:
AutoWiringByNameDependencySetterInjectionDemo.class
/**
* byName Autowiring 依赖 setter 方法注释示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class AutoWiringByNameDependencySetterInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
String xmlResourcePath = "classpath:/META-INF/autowiring-dependency-setter-injection.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 依赖查找并创建 Bean
UserHolder userHolder = defaultListableBeanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
autowiring-dependency-setter-injection.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">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<!-- 如果 autowire = "byType",此时会有两个 type 相同的 bean,但是会关联到 superUser,因为 superUser 设置了 primary-->
<bean class="com.mindartisan.spring.geek.ioc.dependency.injection.UserHolder" autowire="byName">
<!-- 会关联到 id =1,name = Steve 的 bean -->
<!--<property name="user" ref="user"/>-->
</bean>
</beans>
构造器依赖注入
手动方式
- XML 资源配置元信息
- Java 注解配置元信息
- API 配置元信息
相关代码:
XmlDependencyConstructorInjectionDemo.class
/**
* 基于 xml 资源的依赖 Constructor 注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class XmlDependencyConstructorInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
String xmlResourcePath = "classpath:/META-INF/dependency-constructor-injection.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 依赖查找并创建 Bean
UserHolder userHolder = defaultListableBeanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
dependency-constructor-injection.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">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<bean class="com.mindartisan.spring.geek.ioc.dependency.injection.UserHolder">
<!-- 会关联到 id =1,name = Steve 的 bean -->
<constructor-arg name="user" ref="superUser"/>
</bean>
</beans>
AnnotationDependencyConstructorInjectionDemo.class
/**
* 基于注解的依赖 Constructor 注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class AnnotationDependencyConstructorInjectionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类
applicationContext.register(AnnotationDependencyConstructorInjectionDemo.class);
// 将 User Bean 初始化,供 userHolder(User user) 使用
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
// 关闭 Spring 应用上下文
applicationContext.close();
}
// /**
// * 此处采用的构造器方式
// *
// * @param user 用户
// * @return {@link UserHolder}
// */
@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
/**
* 此处采用 setter 方式
*
* @param user 用户
* @return {@link UserHolder}
*/
// @Bean
// public UserHolder userHolder(User user) {
// UserHolder userHolder = new UserHolder();
// userHolder.setUser(user);
// return userHolder;
// }
}
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="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
</bean>
<bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="北京"/>
</bean>
<!-- 延迟查找使用 -->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
ApiDependencyConstructorInjectionDemo.class
/**
* 基于 API 实现依赖 Constructor 注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class ApiDependencyConstructorInjectionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 UserHolder 的 BeanDefinition
BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
// 将 User Bean 初始化
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
// 关闭 Spring 应用上下文
applicationContext.close();
}
/**
* 为 UserHolder 生成 BeanDefinition
*
* @return {@link BeanDefinition}
*/
private static BeanDefinition createUserHolderBeanDefinition() {
// API 用的就是下述代码
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
// 类似 xml 文件中 「constructor-arg」
beanDefinitionBuilder.addConstructorArgReference("superUser");
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
return beanDefinition;
}
}
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="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
</bean>
<bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="北京"/>
</bean>
<!-- 延迟查找使用 -->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
自动方式
- constructor
相关代码:
AutoWiringConstructorDependencyConstructorInjectionDemo.class
/**
* byName Autowiring 依赖 Constructor 注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class AutoWiringConstructorDependencyConstructorInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
String xmlResourcePath = "classpath:/META-INF/autowiring-dependency-constructor-injection.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 依赖查找并创建 Bean
UserHolder userHolder = defaultListableBeanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
autowiring-dependency-constructor-injection.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">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<bean class="com.mindartisan.spring.geek.ioc.dependency.injection.UserHolder" autowire="constructor">
</bean>
</beans>
字段注入
手动模式
- @Autowired
- @Resource
- @Inject(可选)
相关代码:
AnnotationDependencyFieldInjectionDemo.class
/**
* 基于注解的依赖 字段 注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class AnnotationDependencyFieldInjectionDemo {
@Autowired
private
// static // 会忽略掉静态字段
UserHolder userHolder;
@Resource// 静态字段直接报错
private UserHolder userHolder2;
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类(配置类也是 Spring 的 Bean)
applicationContext.register(AnnotationDependencyFieldInjectionDemo.class);
// 将 User Bean 初始化,供 userHolder(User user) 使用
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 AnnotationDependencyFieldInjectionDemo bean
AnnotationDependencyFieldInjectionDemo demoBean = applicationContext.getBean(AnnotationDependencyFieldInjectionDemo.class);
// 通过 @Autowired 将字段关联
UserHolder userHolder = demoBean.userHolder;
System.out.println(userHolder);
UserHolder userHolder2 = demoBean.userHolder2;
System.out.println(userHolder2);
// 单例情况下,两个相同,true
System.out.println(userHolder2 == userHolder);
// 关闭 Spring 应用上下文
applicationContext.close();
}
@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
}
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="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
</bean>
<bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="北京"/>
</bean>
<!-- 延迟查找使用 -->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
方法注入
手动注入
- @Autowired
- @Resource
- @Inject(可选)
- @Bean
相关代码:
AnnotationDependencyMethodInjectionDemo.class
/**
* 基于注解的依赖 方法 注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class AnnotationDependencyMethodInjectionDemo {
private UserHolder userHolder;
private UserHolder userHolder2;
@Autowired
public void method1(UserHolder userHolder) {
this.userHolder = userHolder;
}
@Resource
public void method2(UserHolder userHolder) {
this.userHolder2 = userHolder;
}
@Bean
public UserHolder userHolder(User user) {
return new UserHolder(user);
}
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类(配置类也是 Spring 的 Bean)
applicationContext.register(AnnotationDependencyMethodInjectionDemo.class);
// 将 User Bean 初始化,供 userHolder(User user) 使用
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 AnnotationDependencyFieldInjectionDemo bean
AnnotationDependencyMethodInjectionDemo demoBean = applicationContext.getBean(AnnotationDependencyMethodInjectionDemo.class);
// 通过 @Autowired 将字段关联
UserHolder userHolder = demoBean.userHolder;
System.out.println(userHolder);
UserHolder userHolder2 = demoBean.userHolder2;
System.out.println(userHolder2);
// 单例情况下,两个相同,true
System.out.println(userHolder2 == userHolder);
// 关闭 Spring 应用上下文
applicationContext.close();
}
}
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="user" class="com.mindartisan.spring.geek.ioc.overview.domain.User" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
</bean>
<bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="北京"/>
</bean>
<!-- 延迟查找使用 -->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
回调注入
Aware 系列接口回调
内建接口 | 说明 | 备注 |
---|---|---|
BeanFactoryAware | 获取 IoC 容器 - BeanFactory | |
ApplicationContextAware | 获取 Spring 应用上下文 - ApplicationContext 对象 | |
EnvironmentAware | 获取 Environment 对象 | |
ResourceLoaderAware | 获取资源加载器 对象 - ResourceLoader | |
BeanClassLoaderAware | 获取加载当前 Bean Class 的 ClassLoader | |
BeanNameAware | 获取当前 Bean 的名称 | |
MessageSourceAware | 获取 MessageSource 对象,用于 Spring 国际化 | |
ApplicationEventPublisherAware | 获取 ApplicationEventPublishAware 对象,用于 Spring 事件 | |
EmbeddedValueResolverAware | 获取 StringValueResolver 对象,用于占位符处理 |
相关代码:
AwarelnterfaceDependencyInjectionDemo.class
/**
* 基于 Aware 接口回调的依赖注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class AwarelnterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {
private static BeanFactory beanFactory;
private static ApplicationContext applicationContext;
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册 配置类
context.register(AwarelnterfaceDependencyInjectionDemo.class);
// 启动 Spring 应用上下文
context.refresh();
System.out.println(beanFactory == context.getBeanFactory());
System.out.println(applicationContext == context);
// 关闭 Spring 应用上下文
context.close();
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
AwarelnterfaceDependencyInjectionDemo.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
AwarelnterfaceDependencyInjectionDemo.applicationContext = applicationContext;
}
}
依赖注入类型选择
低依赖: 构造器注入,如果构造器的参数过多就不适合使用构造器注入
多依赖:Setter 方法注入,注入的时间顺序依赖与用户操作,如果字段或者依赖的属性存在依赖关系,可能会有问题
便利性:字段注入
声明类:方法注入,一般使用 @Bean 方法注入
基础类型注入
原生类型(Primitive):boolean、byte、char、short、int、float、long、double
标量类型(Scalar):Number、Character、Boolean、Enum、Locale、Charset、Currency、Properties、UUID
常规类型(General):Object、String、TimeZone、Calendar、Optional 等
Spring 类型:Resource、InputSource、Formatter 等
相关代码:
UserForBasicInject.class
/**
* 用户--用于演示基本类型注入
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class UserForBasicInject {
private Long id;
private String name;
private City city;
// City 和 Resource 相关用于演示基本类型注入
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
private Resource configFileLocation;
public Resource getConfigFileLocation() {
return configFileLocation;
}
public void setConfigFileLocation(Resource configFileLocation) {
this.configFileLocation = configFileLocation;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", city=" + city +
", configFileLocation=" + configFileLocation +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// @Override
// public String toString() {
// return "User{" +
// "id=" + id +
// ", name='" + name + '\'' +
// '}';
// }
/**
* 通过静态方法实例化
*
* @return {@link UserForBasicInject}
*/
public static UserForBasicInject createUser(){
UserForBasicInject user = new UserForBasicInject();
user.setId(1L);
user.setName("Steve");
return user;
}
}
City.class
/**
* 城市--用来作为 User 属性演示基本类型注入
*
* @author mindartisan.blog.csdn.net
* @date
*/
public enum City {
BEIJING,
SHANGHAI,
GUANGZHOU
}
dependency-lookup-context-basic-inject.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="userForBasicInject" class="com.mindartisan.spring.geek.ioc.overview.domain.UserForBasicInject" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
<!--City 和 configFileLocation 用于演示基本类型注入-->
<property name="city" value="BEIJING"/>
<property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
</bean>
<bean id="superUserForBasicInject" class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUserForBasicInject" parent="userForBasicInject"
primary="true">
<property name="address" value="北京"/>
</bean>
<!--延迟查找使用-->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="userForBasicInject"/>
</bean>
</beans>
DependencyLookUpDemoForBasicInject.class
/**
* 依赖查找示例--用于演示基础类型注入
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class DependencyLookUpDemoForBasicInject {
public static void main(String[] args) {
// 配置 XML 配置文件,两个方式均可
// 启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/dependency-lookup-context-basic-inject.xml");
// BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
lookupInRealTime(beanFactory);
lookupInLazy(beanFactory);
lookupSingleByType(beanFactory);
lookupCollectionByType(beanFactory);
lookupByAnnotationType(beanFactory);
}
/**
* 通过名称:实时查找
*
* @param beanFactory bean工厂
*/
private static void lookupInRealTime(BeanFactory beanFactory) {
UserForBasicInject user = (UserForBasicInject) beanFactory.getBean("userForBasicInject");
System.out.println("通过名称,实时查找:" + user);
}
/**
* 通过名称:延迟查找
*
* @param beanFactory bean工厂
*/
private static void lookupInLazy(BeanFactory beanFactory) {
ObjectFactory<UserForBasicInject> objectFactoryCreatingFactoryBean = (ObjectFactory<UserForBasicInject>) beanFactory.getBean("objectFactoryCreatingFactoryBean");
UserForBasicInject user = objectFactoryCreatingFactoryBean.getObject();
System.out.println("通过名称,延迟查找:" + user);
}
/**
* 按类型查找:单个 bean
*
* @param beanFactory bean工厂
*/
private static void lookupSingleByType(BeanFactory beanFactory) {
UserForBasicInject user = beanFactory.getBean(UserForBasicInject.class);
System.out.println("按类型查找,单个 bean:" + user);
}
/**
* 按类型查找:多个 bean
*
* @param beanFactory bean工厂
*/
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
// key 为 bean 名称
Map<String, UserForBasicInject> users = listableBeanFactory.getBeansOfType(UserForBasicInject.class);
System.out.println("按类型查找,多个 bean:" + users);
}
}
/**
* 按注解查找
*
* @param beanFactory bean工厂
*/
private static void lookupByAnnotationType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
// key 为 bean 名称
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("按注解查找:" + users);
}
}
}
SuperUserForBasicInject.class
/**
* 超级用户--用于演示基础类型注入
*
* @author mindartisan.blog.csdn.net
* @date
*/
@Super
public class SuperUserForBasicInject extends UserForBasicInject {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "SuperUser{" +
"address='" + address + '\'' +
"} " + super.toString();
}
}
集合类型注入
数组类型(Array):原生类型、标量类型、常规类型、Spring 类型
集合类型(Collection):
- Collection:List、Set(SortedSet、NavigableSet、EnumSet)
- Map:Properties
相关代码:
City.class,复用基础类型注入
UserForCollectionInject.class
/**
* 用户--用于演示集合类型注入
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class UserForCollectionInject {
private Long id;
private String name;
private City city;
private City[] workCities;
private List<City> lifeCities;
public City[] getWorkCities() {
return workCities;
}
public void setWorkCities(City[] workCities) {
this.workCities = workCities;
}
public List<City> getLifeCities() {
return lifeCities;
}
public void setLifeCities(List<City> lifeCities) {
this.lifeCities = lifeCities;
}
// City 和 Resource 相关用于演示基本类型注入
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
private Resource configFileLocation;
public Resource getConfigFileLocation() {
return configFileLocation;
}
public void setConfigFileLocation(Resource configFileLocation) {
this.configFileLocation = configFileLocation;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "UserForCollectionInject{" +
"id=" + id +
", name='" + name + '\'' +
", city=" + city +
", workCities=" + Arrays.toString(workCities) +
", lifeCities=" + lifeCities +
", configFileLocation=" + configFileLocation +
'}';
}
// @Override
// public String toString() {
// return "User{" +
// "id=" + id +
// ", name='" + name + '\'' +
// '}';
// }
/**
* 通过静态方法实例化
*
* @return {@link UserForCollectionInject}
*/
public static UserForCollectionInject createUser(){
UserForCollectionInject user = new UserForCollectionInject();
user.setId(1L);
user.setName("Steve");
return user;
}
}
DependencyLookUpDemoForCollectionInject.class
/**
* 依赖查找示例--用于演示集合类型注入
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class DependencyLookUpDemoForCollectionInject {
public static void main(String[] args) {
// 配置 XML 配置文件,两个方式均可
// 启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/dependency-lookup-context-collection" +
"-inject" +
".xml");
// BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
lookupInRealTime(beanFactory);
lookupInLazy(beanFactory);
lookupSingleByType(beanFactory);
lookupCollectionByType(beanFactory);
lookupByAnnotationType(beanFactory);
}
/**
* 通过名称:实时查找
*
* @param beanFactory bean工厂
*/
private static void lookupInRealTime(BeanFactory beanFactory) {
UserForCollectionInject user = (UserForCollectionInject) beanFactory.getBean("userForCollectionInject");
System.out.println("通过名称,实时查找:" + user);
}
/**
* 通过名称:延迟查找
*
* @param beanFactory bean工厂
*/
private static void lookupInLazy(BeanFactory beanFactory) {
ObjectFactory<UserForCollectionInject> objectFactoryCreatingFactoryBean = (ObjectFactory<UserForCollectionInject>) beanFactory.getBean("objectFactoryCreatingFactoryBean");
UserForCollectionInject user = objectFactoryCreatingFactoryBean.getObject();
System.out.println("通过名称,延迟查找:" + user);
}
/**
* 按类型查找:单个 bean
*
* @param beanFactory bean工厂
*/
private static void lookupSingleByType(BeanFactory beanFactory) {
UserForCollectionInject user = beanFactory.getBean(UserForCollectionInject.class);
System.out.println("按类型查找,单个 bean:" + user);
}
/**
* 按类型查找:多个 bean
*
* @param beanFactory bean工厂
*/
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
// key 为 bean 名称
Map<String, UserForCollectionInject> users = listableBeanFactory.getBeansOfType(UserForCollectionInject.class);
System.out.println("按类型查找,多个 bean:" + users);
}
}
/**
* 按注解查找
*
* @param beanFactory bean工厂
*/
private static void lookupByAnnotationType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
// key 为 bean 名称
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("按注解查找:" + users);
}
}
}
dependency-lookup-context-collection-inject.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="userForCollectionInject" class="com.mindartisan.spring.geek.ioc.overview.domain.UserForCollectionInject"
autowire="byName">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
<property name="city" value="BEIJING"/>
<property name="workCities" value="BEIJING,SHANGHAI"/>
<!--<property name="lifeCities" value="BEIJING,GUANGZHOU,SHANGHAI"/>-->
<property name="lifeCities">
<list>
<value>BEIJING</value>
<value>GUANGZHOU</value>
<value>SHANGHAI</value>
</list>
</property>
<property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
</bean>
<bean id="superUserForCollectionInject"
class="com.mindartisan.spring.geek.ioc.overview.domain.SuperUserForCollectionInject"
parent="userForCollectionInject"
primary="true">
<property name="address" value="北京"/>
</bean>
<!--延迟查找使用-->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="userForCollectionInject"/>
</bean>
</beans>
UserForCollectionInject.class
/**
* 用户--用于演示集合类型注入
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class UserForCollectionInject {
private Long id;
private String name;
private City city;
private City[] workCities;
private List<City> lifeCities;
public City[] getWorkCities() {
return workCities;
}
public void setWorkCities(City[] workCities) {
this.workCities = workCities;
}
public List<City> getLifeCities() {
return lifeCities;
}
public void setLifeCities(List<City> lifeCities) {
this.lifeCities = lifeCities;
}
// City 和 Resource 相关用于演示基本类型注入
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
private Resource configFileLocation;
public Resource getConfigFileLocation() {
return configFileLocation;
}
public void setConfigFileLocation(Resource configFileLocation) {
this.configFileLocation = configFileLocation;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "UserForCollectionInject{" +
"id=" + id +
", name='" + name + '\'' +
", city=" + city +
", workCities=" + Arrays.toString(workCities) +
", lifeCities=" + lifeCities +
", configFileLocation=" + configFileLocation +
'}';
}
// @Override
// public String toString() {
// return "User{" +
// "id=" + id +
// ", name='" + name + '\'' +
// '}';
// }
/**
* 通过静态方法实例化
*
* @return {@link UserForCollectionInject}
*/
public static UserForCollectionInject createUser(){
UserForCollectionInject user = new UserForCollectionInject();
user.setId(1L);
user.setName("Steve");
return user;
}
}
限定注入
使用注解 @Qualifier 限定
- 通过 Bean 名称限定
- 通过分组限定
相关代码:
QualifierAnnotationDependencyInjectDemo.class
/**
* Qualifier 注解依赖注入示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class QualifierAnnotationDependencyInjectDemo {
@Autowired // 会注入 superUser,因为 primary = true
private User user;
@Autowired
@Qualifier("user") // 指定 bean 名称或者 id
private User namedUser;
@Bean
@Qualifier // 逻辑分组
public User user1() {
return createUser(101L);
}
@Bean
@Qualifier // 逻辑分组
public User user2() {
return createUser(102L);
}
// 上述定义了 4 个 User 类型的 Bean:superUser、user、user1、user2
@Autowired
private Collection<User> allUsers; // 两个 Bean:user+namedUser
@Autowired
@Qualifier // 逻辑分组
private Collection<User> qualifierUsers; // 没用 @UserGroup 之前:2 个 bean 标注了 @Qualifier 注解的 user1 user2;用了之后 4
// 个:user1、user2、user3、user4
// 下述演示 @Qualifier 分组限定
private static User createUser(Long id) {
User user = new User();
user.setId(id);
return user;
}
@Bean
@UserGroup
public User user3() {
return createUser(103L);
}
@Bean
@UserGroup
public User user4() {
return createUser(104L);
}
@Bean
@UserGroup
public User user5() {
return createUser(105L);
}
@Autowired
@UserGroup
private Collection<User> userGroup; // 3 个 Bean,user3、user4、user5
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类(配置类也是 Spring 的 Bean)
applicationContext.register(QualifierAnnotationDependencyInjectDemo.class);
// 将 User Bean 初始化,供 userHolder(User user) 使用
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 AnnotationDependencyFieldInjectionDemo bean
QualifierAnnotationDependencyInjectDemo demoBean = applicationContext.getBean(QualifierAnnotationDependencyInjectDemo.class);
System.out.println("demoBean.user" + demoBean.user);
System.out.println("demoBean.namedUser" + demoBean.namedUser);
System.out.println("demoBean.allUsers" + demoBean.allUsers);
System.out.println("demoBean.qualifierUsers" + demoBean.qualifierUsers);
System.out.println("demoBean.userGroup" + demoBean.userGroup);
// 关闭 Spring 应用上下文
applicationContext.close();
}
}
UserGroup.class
/**
* 用户组 注解,扩展 @Qualifier
*
* @author mindartisan.blog.csdn.net
* @date
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface UserGroup {
}
基于注解 @Qualifier 扩展限定
- 自定义注解:如 Spring Cloud 的 @LoadBalanced
一个有 负载均衡 能力的 RestTemplate,一个没有 负载均衡 能力的 RestTemplate
延迟依赖注入
使用 API ObjectFactory 延迟注入
使用 API ObjectProvider 延迟注入(推荐)
单一类型、集合类型
相关代码:
LazyAnnotationDependencyInjectDemo.class
/**
* 使用 ObjectProvider 实现延迟注入
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class LazyAnnotationDependencyInjectDemo {
@Autowired
private User user; // 实时注入
@Autowired
private ObjectProvider<User> userObjectProvider;
@Autowired
private ObjectFactory<Collection<User>> collectionObjectFactory;
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类(配置类也是 Spring 的 Bean)
applicationContext.register(LazyAnnotationDependencyInjectDemo.class);
// 将 User Bean 初始化,供 userHolder(User user) 使用
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 AnnotationDependencyFieldInjectionDemo bean
LazyAnnotationDependencyInjectDemo demoBean = applicationContext.getBean(LazyAnnotationDependencyInjectDemo.class);
System.out.println("demoBean.user" + demoBean.user);
System.out.println("demoBean.userObjectProvider" + demoBean.userObjectProvider.getObject());
System.out.println("------");
demoBean.userObjectProvider.forEach(System.out::println);
System.out.println("-------");
System.out.println("demoBean.collectionObjectFactory" + demoBean.collectionObjectFactory.getObject());
demoBean.collectionObjectFactory.getObject().forEach(System.out::println);
// 关闭 Spring 应用上下文
applicationContext.close();
}
}
依赖处理过程
基础知识
入口:DefaultListableBeanFactory#resolveDependency
依赖描述符:DependencyDescriptor
自动绑定候选对象处理器:AutowireCandidateResolver
DependencyDescriptor
public class DependencyDescriptor extends InjectionPoint implements Serializable {
private final Class<?> declaringClass; // 当前要注入的容器(声明的类)
@Nullable // 可以为空,Spring 注解
private String methodName; // 方法名称
@Nullable // 可以为空,Spring 注解
private Class<?>[] parameterTypes; // 构造器参数或方法参数
private int parameterIndex; // 参数的索引
@Nullable // 可以为空,Spring 注解
private String fieldName; // 属性名
private final boolean required; //@Autowired 注解的 required 对应
private final boolean eager; // 是否延迟:Lazy = true -> eager = false
private int nestingLevel = 1;
@Nullable
private Class<?> containingClass; // 注入到哪个类里了
@Nullable
private transient volatile ResolvableType resolvableType; // Spring 的泛型输出
@Nullable
private transient volatile TypeDescriptor typeDescriptor;
// 省略方法
}
相关代码:
AnnotationDependencyInjectResolutionDemo.class
/**
* 注解驱动的依赖注入处理流程示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class AnnotationDependencyInjectResolutionDemo {
/**
* 单一注入:
* 依赖应找(处理)
* DependencyDescriptor->
* 必须(required = true)
* 实时注入(eager=true)
* 通过类型(User.class)
* 字段名称(“user")
* 是否首要(primary = true)
*/
@Autowired
private User user;
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类(配置类也是 Spring 的 Bean)
applicationContext.register(AnnotationDependencyInjectResolutionDemo.class);
// 将 User Bean 初始化,供 userHolder(User user) 使用
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 AnnotationDependencyFieldInjectionDemo bean
AnnotationDependencyInjectResolutionDemo demoBean = applicationContext.getBean(AnnotationDependencyInjectResolutionDemo.class);
System.out.println("demoBean.user" + demoBean.user);
// 关闭 Spring 应用上下文
applicationContext.close();
}
}
debug 验证
断点位置:DefaultListableBeanFactory#resolveDependency() -> descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 断点在下一行
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
在当前示例下,前几个 if 都为 false,直接进入最后的 else,result 此时也会为 null,直接进入
doResolveDependency()
查看。
断点位置:DefaultListableBeanFactory#doResolveDependency() -> InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 断点在下一行
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 是否多个 Bean
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 此时会有两个 bean:user、superUser
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
DefaultListableBeanFactory#findAutowireCandidates()
找符合类型的 bean,此例中是 user,会有两个 user 和 superUser
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
DefaultListableBeanFactory#determinePrimaryCandidate()
主要是找 primary bean
protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String primaryBeanName = null;
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (isPrimary(candidateBeanName, beanInstance)) {
if (primaryBeanName != null) {
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
if (candidateLocal && primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"more than one 'primary' bean found among candidates: " + candidates.keySet());
}
else if (candidateLocal) {
primaryBeanName = candidateBeanName;
}
}
else {
primaryBeanName = candidateBeanName;
}
}
}
return primaryBeanName;
}
DefaultListableBeanFactory#isPrimary()
在这里利用 BeanDefinition 里的 isPrimary 判断
protected boolean isPrimary(String beanName, Object beanInstance) {
String transformedBeanName = transformedBeanName(beanName);
if (containsBeanDefinition(transformedBeanName)) {
return getMergedLocalBeanDefinition(transformedBeanName).isPrimary();
}
BeanFactory parent = getParentBeanFactory();
return (parent instanceof DefaultListableBeanFactory &&
((DefaultListableBeanFactory) parent).isPrimary(transformedBeanName, beanInstance));
}
如果在 AnnotationDependencyInjectResolutionDemo.class 添加:
/*
* 集合注入
*
*/
@Autowired
private Map<String, User> users;
则可以在 DefaultListableBeanFactory#resolveMultipleBeans() 方法打断点查看,不再赘述。
else if (Map.class == type) {
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class<?> keyType = mapType.resolveGeneric(0);
// 省略代码
}
如果在 AnnotationDependencyInjectResolutionDemo.class 添加:
@Autowired
private Optional<User> optionalUser;
则可以在 DefaultListableBeanFactory#createOptionalDependency() 方法打断点查看,不再赘述。
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
@Autowired 注入原理
大概流程:
- 元信息解析 -> 和 DependencyDescriptor 相关
- 依赖查找 -> 可以理解为依赖处理的过程
- 依赖注入(注入到方法、字段)
源码解析
以「依赖处理流程」中的代码为例,断点在 DefaultListableBeanFactory#resolveDependency() -> descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
使用 IDEA 的 debug 工具,查看调用栈相关信息:
进入方法:
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 此处进行依赖处理的流程
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
// 通过反射的形式对 field 赋值
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
一些细节:
主要引用了 极客时间 Spring IoC 课程 中的一些精选评论。
引用一:
- 在doCreateBean中会先调用applyMergedBeanDefinitionPostProcessors,后执行populateBean 所以会先调用postProcessMergedBeanDefinition后执行InstantiationAwareBeanPostProcessor的postProcessProperties。
- postProcessProperties中有两个步骤:
- findAutowiringMetadata查找注入元数据,没有缓存就创建,具体是上一节内容。最终会返回InjectionMetadata,里面包括待注入的InjectedElement信息(field、method)等等
- 执行InjectionMetadata的inject方法,具体为AutowiredFieldElement和AutowiredMethodElement的Inject方法
- AutowiredFieldElement inject具体流程:
- DependencyDescriptor的创建
- 调用beanFactory的resolveDependency获取带注入的bean
- resolveDependency根据具体类型返回候选bean的集合或primary 的bean
- 利用反射设置field
引用二:
引用三:
JSR-330 @Inject 注入原理
如果 JSR-330 存在与 ClassPath 中,复用AutowiredAnnotationBeanPostProcessor
实现 ```java private final Set> autowiredAnnotationTypes = new LinkedHashSet<>(4);
- AutowiredFieldElement inject具体流程:
/**
* Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
* standard {@link Autowired @Autowired} and {@link Value @Value} annotations.
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
* if available.
*/
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
在使用时,优先使用 `@Autowired`,参见:
```java
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
Java 通用注解注入原理
基础知识
基于 CommonAnnotationBeanPostProcessor
实现:
- 注入注解
- javax.xml.ws.WebServiceRef
- javax.ejb.EJB
- javax.annotation.Resource
- 生命周期注解
再详细对比下此方法 postProcessMergedBeanDefinition:
// CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
// AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
再去 super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName)
里看下:
// InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition(beanDefinition, beanType, beanName)
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}
可以看到,CommonAnotationBeanPostProcessor 比 AutowiredAnnotationBeanPostProcessor 的处理流程其实差不多,当前可以看到多的有LifecycleMetadata
的处理:
/**
* Class representing information about annotated init and destroy methods.
*/
private class LifecycleMetadata {
private final Class<?> targetClass;
private final Collection<LifecycleElement> initMethods;
private final Collection<LifecycleElement> destroyMethods;
@Nullable
private volatile Set<LifecycleElement> checkedInitMethods;
@Nullable
private volatile Set<LifecycleElement> checkedDestroyMethods;
public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods,
Collection<LifecycleElement> destroyMethods) {
this.targetClass = targetClass;
this.initMethods = initMethods;
this.destroyMethods = destroyMethods;
}
}
注入源码解析
回到 Java 通用注解注入原理的问题中来,调用链:
- CommonAnotationBeanPostProcessor#postProcessProperties();
- CommonAnotationBeanPostProcessor#findResourceMetadata();
- CommonAnotationBeanPostProcessor#buildResourceMetadata();
CommonAnotationBeanPostProcessor#buildResourceMetadata() 相关代码:
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
回调源码解析
构造器:
/**
* Create a new CommonAnnotationBeanPostProcessor,
* with the init and destroy annotation types set to
* {@link javax.annotation.PostConstruct} and {@link javax.annotation.PreDestroy},
* respectively.
*/
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
// 下面两行
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
// 上面两行
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
this.initAnnotationType = initAnnotationType;
}
public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
this.destroyAnnotationType = destroyAnnotationType;
}
查找 initAnnotationType
的 usage,发现是 CommonAnotationBeanPostProcessor#buildResourceMetadata()
,相关代码:
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
// 重点看此处代码:下述代码会处理被「@PostConstruct 以及 @PreDestroy」的方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
再来看下 LifecycleElement:
private static class LifecycleElement {
private final Method method;
private final String identifier;
public LifecycleElement(Method method) {
if (method.getParameterCount() != 0) {
throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);
}
this.method = method;
this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
ClassUtils.getQualifiedMethodName(method) : method.getName());
}
public void invoke(Object target) throws Throwable {
ReflectionUtils.makeAccessible(this.method);
this.method.invoke(target, (Object[]) null);
}
// 省略部分代码
}
查找 invoke 方法的 usages,会发现是 InitDestroyAnnotationBeanPostProcessor#invokeInitMethods() 以及 InitDestroyAnnotationBeanPostProcessor#invokeDestroyMethods()。
再查找上述两个方法的 usage,会发现分别是 postProcessBeforeInitialization()
以及 postProcessBeforeDestruction()
方法。
CommonAnotationBeanPostProcessor 与 AutowiredAnnotationBeanPostProcessor 顺序
二者都实现了 Ordered
接口:
- CommonAnotationBeanPostProcessor 的 order 为
private int order = Ordered.LOWEST_PRECEDENCE - 3;
,倒数第四位 - AutowiredAnnotationBeanPostProcessor 的 order 为
private int order = Ordered.LOWEST_PRECEDENCE - 2;
,倒数第三位
所以:CommonAnotationBeanPostProcessor 会在 AutowiredAnnotationBeanPostProcessor 使用
自定义依赖注入注解
基于 AutowiredAnnotationBeanPostProcessor 实现
自定义个注解:MyAutowired.class
/**
* 自定义注解,利用了 @Autowired
*
* @author mindartisan.blog.csdn.net
* @date
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MyAutowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
InjectedUser.class
/**
* 自定义依赖注入注解
*
* @author mindartisan.blog.csdn.net
* @date
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InjectedUser {
}
主程序:MyAnnotationDependencyInjectResolutionDemo.class
/**
* 注解驱动的依赖注入处理流程示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class MyAnnotationDependencyInjectResolutionDemo {
/**
* 单一注入:
* 依赖应找(处理)
* DependencyDescriptor->
* 必须(required = true)
* 实时注入(eager=true)
* 通过类型(User.class)
* 字段名称(“user")
* 是否首要(primary = true)
*/
@Autowired
private User user;
@MyAutowired
private User myAutowiredUser;
@Inject
private User injectUser;
@InjectedUser
private User myInjectUser;
// @Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
// public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
// AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor =
// new AutowiredAnnotationBeanPostProcessor();
// // 新的自定义注解+自带的实现
// // 存在的问题,Inject 或者其他需要的注解不存在
// Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(asList(Autowired.class,
// Inject.class, InjectedUser.class));
// autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
// return autowiredAnnotationBeanPostProcessor;
// }
@Bean
@Order(Ordered.LOWEST_PRECEDENCE - 3)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor =
new AutowiredAnnotationBeanPostProcessor();
autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
return autowiredAnnotationBeanPostProcessor;
}
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 配置类(配置类也是 Spring 的 Bean)
applicationContext.register(MyAnnotationDependencyInjectResolutionDemo.class);
// 将 User Bean 初始化,供 userHolder(User user) 使用
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
xmlBeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 AnnotationDependencyFieldInjectionDemo bean
MyAnnotationDependencyInjectResolutionDemo demoBean = applicationContext.getBean(MyAnnotationDependencyInjectResolutionDemo.class);
System.out.println("demoBean.user" + "=" + demoBean.user);
System.out.println("demoBean.injectUser" + "=" + demoBean.injectUser);
System.out.println("demoBean.myAutowiredUser" + "=" + demoBean.myAutowiredUser);
System.out.println("demoBean.myInjectUser" + "=" + demoBean.myInjectUser);
// 关闭 Spring 应用上下文
applicationContext.close();
}
}
主要是因为下面的代码(选下面的)
@Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor =
new AutowiredAnnotationBeanPostProcessor();
// 新的自定义注解+自带的实现
// 存在的问题:Inject 或者其他需要的注解不存在
Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(asList(Autowired.class,
Inject.class, InjectedUser.class));
autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
return autowiredAnnotationBeanPostProcessor;
}
@Bean
@Order(Ordered.LOWEST_PRECEDENCE - 3)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor =
new AutowiredAnnotationBeanPostProcessor();
autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
return autowiredAnnotationBeanPostProcessor;
}
自定义实现
这里没有讲
生命周期处理:
- InstantiationAwareBeanPostProcessor
- MergedBeanDefinitionPostProcessor
元数据:
- InjectedElement
- InjectionMetadata