1.写在前面

前面的博客我们已经写了Spring的依赖查找,这篇博客我们来了解写Spring的依赖注入。

2.依赖注入的模式和类型

手动模式 - 配置或者编程的方式, 提前安排注入规则

  • XML 资源配置元信息
  • Java 注解配置元信息
  • API 配置元信息

自动模式 - 实现方提供依赖自动关联的方式, 按照內建的注入规则

  • Autowiring( 自动绑定)

依赖注入的类型

3.自动绑定( 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 之间的关系。 您可以让 Spring 通过检查 ApplicationContext 的内容自动为您的 bean 解析协作者(其他 bean)。

优点

  • Autowiring can significantly reduce the need to specify properties or constructor arguments.(自动装配可以显着减少指定属性或构造函数参数的需要。)
  • Autowiring can update a configuration as your objects evolve.(随着对象的发展,自动装配可以更新配置。)

4.自动绑定( Autowiring) 模式

5.自动绑定( Autowiring) 限制和不足

官方说明

  • Limitations and Disadvantages of Autowiring 小节

6.Setter 方法注入

实现方法

  • 手动模式

    • XML 资源配置元信息
    • Java 注解配置元信息
    • API 配置元信息
  • 自动模式
    • byName
    • byType

下面我们来展示各种代码,具体的如下:

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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="classpath:/META-INF/dependency-lookup-context.xml"/><bean class="org.learn.spring.dependency.injection.UserHolder"><property name="user" ref="superUser"/></bean></beans>
package org.learn.spring.dependency.injection;import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;// 基于 xml 的setter依赖注入的示例
public class XmlDependencySetterInjectionDemo {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);String xmlResourcePath = "classpath:/META-INF/dependency-setter-injection.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 创建依赖查找并且创建BeanUserHolder userHolder = beanFactory.getBean(UserHolder.class);System.out.println(userHolder);}
}

Java 注解配置元信息

package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;import java.util.Map;// 基于 Annotation 的setter依赖注入的示例
public class AnnotationDependencySetterInjectionDemo {public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类applicationContext.register(AnnotationDependencySetterInjectionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 创建依赖查找并且创建BeanUserHolder userHolder = applicationContext.getBean(UserHolder.class);System.out.println(userHolder);// 显示的关闭spring应用上下文applicationContext.close();}@Beanpublic UserHolder userHolder(User user){UserHolder userHolder = new UserHolder();userHolder.setUser(user);return userHolder;}
}

API 配置元信息

package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;// 基于 API 的setter依赖注入的示例
public class ApiDependencySetterInjectionDemo {public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 生成UserHolder 的BeanDefinitionBeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();// 注册UserHolder 的BeanDefinitionapplicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 创建依赖查找并且创建BeanUserHolder userHolder = applicationContext.getBean(UserHolder.class);System.out.println(userHolder);// 显示的关闭spring应用上下文applicationContext.close();}// 为UserHolder生成BeanDefinitionprivate static BeanDefinition createUserHolderBeanDefinition() {BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);beanDefinitionBuilder.addPropertyReference("user", "superUser");return beanDefinitionBuilder.getBeanDefinition();}}

byName

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="classpath:/META-INF/dependency-lookup-context.xml"/><bean class="org.learn.spring.dependency.injection.UserHolder" autowire="byName"/></beans>
package org.learn.spring.dependency.injection;import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;// byName AutoWring 依赖 setter方法注入示例
public class AutoWringByNameDependencySetterInjectionDemo {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);String xmlResourcePath = "classpath:/META-INF/autowring-dependency-setter-injection.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 创建依赖查找并且创建BeanUserHolder userHolder = beanFactory.getBean(UserHolder.class);System.out.println(userHolder);}}

byType

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="classpath:/META-INF/dependency-lookup-context.xml"/><bean class="org.learn.spring.dependency.injection.UserHolder" autowire="byType"/></beans>
package org.learn.spring.dependency.injection;import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;// byName AutoWring 依赖 setter方法注入示例
public class AutoWringByNameDependencySetterInjectionDemo {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);String xmlResourcePath = "classpath:/META-INF/autowring-dependency-setter-injection.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 创建依赖查找并且创建BeanUserHolder userHolder = beanFactory.getBean(UserHolder.class);System.out.println(userHolder);}}

7.构造器注入

实现方法

  • 手动模式

    • XML 资源配置元信息
    • Java 注解配置元信息
    • API 配置元信息
  • 自动模式
    • constructor

下面来展示示例代码

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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="classpath:/META-INF/dependency-lookup-context.xml"/><bean class="org.learn.spring.dependency.injection.UserHolder"><constructor-arg name="user" ref="superUser"/></bean></beans>
package org.learn.spring.dependency.injection;import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;// 基于 xml 的Constructor依赖注入的示例
public class XmlDependencyConstructorInjectionDemo {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);String xmlResourcePath = "classpath:/META-INF/dependency-constructor-injection.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 创建依赖查找并且创建BeanUserHolder userHolder = beanFactory.getBean(UserHolder.class);System.out.println(userHolder);}
}

Java 注解配置元信息

package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;// 基于 Annotation 的Constructor依赖注入的示例
public class AnnotationDependencyConstructorInjectionDemo {public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类applicationContext.register(AnnotationDependencyConstructorInjectionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 创建依赖查找并且创建BeanUserHolder userHolder = applicationContext.getBean(UserHolder.class);System.out.println(userHolder);// 显示的关闭spring应用上下文applicationContext.close();}@Beanpublic UserHolder userHolder(User user){return new UserHolder(user);}
}

API 配置元信息

package org.learn.spring.dependency.injection;import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;// 基于 API 的Constructor依赖注入的示例
public class ApiDependencyConstructorInjectionDemo {public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 生成UserHolder 的BeanDefinitionBeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();// 注册UserHolder 的BeanDefinitionapplicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 创建依赖查找并且创建BeanUserHolder userHolder = applicationContext.getBean(UserHolder.class);System.out.println(userHolder);// 显示的关闭spring应用上下文applicationContext.close();}// 为UserHolder生成BeanDefinitionprivate static BeanDefinition createUserHolderBeanDefinition() {BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);beanDefinitionBuilder.addConstructorArgReference("superUser");return beanDefinitionBuilder.getBeanDefinition();}}

constructor

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="classpath:/META-INF/dependency-lookup-context.xml"/><bean class="org.learn.spring.dependency.injection.UserHolder" autowire="constructor"/></beans>
package org.learn.spring.dependency.injection;import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;// constructor AutoWring 依赖 constructor方法注入示例
public class AutoWringConstructorDependencyConstructorInjectionDemo {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);String xmlResourcePath = "classpath:/META-INF/autowring-dependency-constructor-injection.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 创建依赖查找并且创建BeanUserHolder userHolder = beanFactory.getBean(UserHolder.class);System.out.println(userHolder);}}

8.字段注入

实现方法

  • 手动模式
  • Java 注解配置元信息
    • @Autowired
    • @Resource
    • @Inject( 可选)

具体的代码如下:

@Autowired

package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;// 基于 Annotation 的Field依赖注入的示例
public class AnnotationDependencyFieldInjectionDemo {@Autowired // @Autowired 会忽略静态字段private UserHolder userHolder;public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyFieldInjectionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 AnnotationDependencyFieldInjectionDemo BeanAnnotationDependencyFieldInjectionDemo demo = applicationContext.getBean(AnnotationDependencyFieldInjectionDemo.class);// 通过@Autowired字段关联UserHolder userHolder = demo.userHolder;System.out.println(userHolder);// 显示的关闭spring应用上下文applicationContext.close();}@Beanpublic UserHolder userHolder(User user){return new UserHolder(user);}
}

@Resource

package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;import javax.annotation.Resource;// 基于 Annotation 的Field依赖注入的示例
public class AnnotationDependencyFieldInjectionDemo {@Autowired // @Autowired 会忽略静态字段private UserHolder userHolder;@Resourceprivate UserHolder userHolder2;public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyFieldInjectionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 AnnotationDependencyFieldInjectionDemo BeanAnnotationDependencyFieldInjectionDemo demo = applicationContext.getBean(AnnotationDependencyFieldInjectionDemo.class);// 通过@Autowired字段关联UserHolder userHolder = demo.userHolder;System.out.println(userHolder);// 通过@Resource字段关联UserHolder userHolder2 = demo.userHolder2;System.out.println(userHolder2);// 显示的关闭spring应用上下文applicationContext.close();}@Beanpublic UserHolder userHolder(User user){return new UserHolder(user);}
}

9.方法注入

实现方法

  • 手动模式

    • Java 注解配置元信息

      • @Autowired
      • @Resource
      • @Inject( 可选)
      • @Bean

具体的代码如下:

package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;import javax.annotation.Resource;// 基于 Annotation 的Method依赖注入的示例
public class AnnotationDependencyMethodInjectionDemo {private UserHolder userHolder;private UserHolder userHolder2;@Autowiredpublic void init1(UserHolder userHolder){this.userHolder = userHolder;}@Resourcepublic void init2(UserHolder userHolder2){this.userHolder2 = userHolder2;}public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyMethodInjectionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 AnnotationDependencyFieldInjectionDemo BeanAnnotationDependencyMethodInjectionDemo demo = applicationContext.getBean(AnnotationDependencyMethodInjectionDemo.class);// 通过@Autowired字段关联UserHolder userHolder = demo.userHolder;System.out.println(userHolder);// 通过@Resource字段关联UserHolder userHolder2 = demo.userHolder2;System.out.println(userHolder2);System.out.println(userHolder == userHolder2);// 显示的关闭spring应用上下文applicationContext.close();}@Beanpublic UserHolder userHolder(User user){return new UserHolder(user);}
}

10.接口回调注入

Aware 系列接口回调

自动模式

具体的代码如下:

package org.learn.spring.dependency.injection;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;// 基于 Aware 的接口回调依赖注入的示例
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {private static BeanFactory beanFactory;private static ApplicationContext applicationContext;public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring Beancontext.register(AwareInterfaceDependencyInjectionDemo.class);// 启动应用上下文context.refresh();System.out.println(beanFactory == context.getBeanFactory());System.out.println(applicationContext == context);// 显示的关闭spring应用上下文context.close();}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;}
}

11.依赖注入类型选择

注入选型

  • 低依赖: 构造器注入
  • 多依赖: Setter 方法注入
  • 便利性: 字段注入
  • 声明类: 方法注入

12.基础类型注入

基础类型

  • 原生类型( 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 等

具体的代码如下:

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="org.learn.spring.ioc.overview.domain.User"><property name="id" value="1"/><property name="name" value="胡桃"/><property name="city" value="HANGZHOU"/><property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/></bean><bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"><property name="targetBeanName" value="user"/></bean><bean id="superUser" class="org.learn.spring.ioc.overview.domain.SuperUser" parent="user" primary="true"><property name="address" value="璃月"/></bean>
</beans>
package org.learn.spring.ioc.overview.domain;import org.learn.spring.ioc.overview.enums.City;
import org.springframework.core.io.Resource;import java.util.Arrays;
import java.util.List;// 用户类
public class User {private Long id;private String name;private City city;private Resource 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;}public City getCity() {return city;}public void setCity(City city) {this.city = city;}public Resource getConfigFileLocation() {return configFileLocation;}public void setConfigFileLocation(Resource configFileLocation) {this.configFileLocation = configFileLocation;}public static User createUser(){User user = new User();user.setId(1L);user.setName("温蒂");return user;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", city=" + city +", configFileLocation=" + configFileLocation +'}';}
}

package org.learn.spring.ioc.overview.dependency.lookup;import org.learn.spring.ioc.overview.annotation.Super;
import org.learn.spring.ioc.overview.domain.SuperUser;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.Map;// 依赖查找的示例
public class DependencyLookupDemo {public static void main(String[] args) {// 配置XML 配置文件// 启动spring的应用上下文BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/dependency-lookup-context.xml");// 1.按照名称查找lookupInRealTime(beanFactory);lookupInLazy(beanFactory);// 2.按照类型查找lookupByType(beanFactory);lookupCollectionByType(beanFactory);// 3.按照类型和名称查找lookupByNameAndType(beanFactory);// 4.通过注解查找对象lookupCollectionByAnnotation(beanFactory);}// 实时查找private static void lookupInRealTime(BeanFactory beanFactory) {User user = (User) beanFactory.getBean("user");System.out.println("实时查找:" + user);}// 延时查找private static void lookupInLazy(BeanFactory beanFactory) {ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");User user = objectFactory.getObject();System.out.println("延时查找:" + user);}// 按照类型查找private static void lookupByType(BeanFactory beanFactory) {User user = beanFactory.getBean(User.class);System.out.println("按照类型查找单一对象:" + user);}// 按照类型查找集合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);}}// 按照类型和名称private static void lookupByNameAndType(BeanFactory beanFactory) {User user = beanFactory.getBean("user", User.class);System.out.println("按照类型和名称查找:" + user);}// 按照注解查找集合对象private static void lookupCollectionByAnnotation(BeanFactory beanFactory) {if (beanFactory instanceof ListableBeanFactory) {ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);System.out.println("按照注解查找到的所有的标注@SuperUser User 集合对象:" + users);}}
}

13.集合类型注入

集合类型

  • 数组类型( Array) : 原生类型、 标量类型、 常规类型、 Spring 类型
  • 集合类型( Collection)
    • Collection: List、 Set( SortedSet、 NavigableSet、 EnumSet)
    • Map: Properties

具体的代码如下:

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="org.learn.spring.ioc.overview.domain.User"><property name="id" value="1"/><property name="name" value="胡桃"/><property name="city" value="HANGZHOU"/><property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/><property name="workCities" value="BEIJING,HANGZHOU"/><property name="lifeCities"><list><value>BEIJING</value><value>HANGZHOU</value><value>SHANGHAI</value></list></property></bean><bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"><property name="targetBeanName" value="user"/></bean><bean id="superUser" class="org.learn.spring.ioc.overview.domain.SuperUser" parent="user" primary="true"><property name="address" value="璃月"/></bean>
</beans>
package org.learn.spring.ioc.overview.domain;import org.learn.spring.ioc.overview.enums.City;
import org.springframework.core.io.Resource;import java.util.Arrays;
import java.util.List;// 用户类
public class User {private Long id;private String name;private City city;private City[] workCities;private List<City> lifeCities;private Resource 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;}public City getCity() {return city;}public void setCity(City city) {this.city = city;}public Resource getConfigFileLocation() {return configFileLocation;}public void setConfigFileLocation(Resource configFileLocation) {this.configFileLocation = configFileLocation;}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;}public static User createUser(){User user = new User();user.setId(1L);user.setName("温蒂");return user;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", city=" + city +", workCities=" + Arrays.toString(workCities) +", lifeCities=" + lifeCities +", configFileLocation=" + configFileLocation +'}';}
}
package org.learn.spring.ioc.overview.dependency.lookup;import org.learn.spring.ioc.overview.annotation.Super;
import org.learn.spring.ioc.overview.domain.SuperUser;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.Map;// 依赖查找的示例
public class DependencyLookupDemo {public static void main(String[] args) {// 配置XML 配置文件// 启动spring的应用上下文BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:META-INF/dependency-lookup-context.xml");// 1.按照名称查找lookupInRealTime(beanFactory);lookupInLazy(beanFactory);// 2.按照类型查找lookupByType(beanFactory);lookupCollectionByType(beanFactory);// 3.按照类型和名称查找lookupByNameAndType(beanFactory);// 4.通过注解查找对象lookupCollectionByAnnotation(beanFactory);}// 实时查找private static void lookupInRealTime(BeanFactory beanFactory) {User user = (User) beanFactory.getBean("user");System.out.println("实时查找:" + user);}// 延时查找private static void lookupInLazy(BeanFactory beanFactory) {ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");User user = objectFactory.getObject();System.out.println("延时查找:" + user);}// 按照类型查找private static void lookupByType(BeanFactory beanFactory) {User user = beanFactory.getBean(User.class);System.out.println("按照类型查找单一对象:" + user);}// 按照类型查找集合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);}}// 按照类型和名称private static void lookupByNameAndType(BeanFactory beanFactory) {User user = beanFactory.getBean("user", User.class);System.out.println("按照类型和名称查找:" + user);}// 按照注解查找集合对象private static void lookupCollectionByAnnotation(BeanFactory beanFactory) {if (beanFactory instanceof ListableBeanFactory) {ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);System.out.println("按照注解查找到的所有的标注@SuperUser User 集合对象:" + users);}}
}

14.限定注入

使用注解 @Qualifier 限定

  • 通过 Bean 名称限定
  • 通过分组限定

基于注解 @Qualifier 扩展限定

  • 自定义注解 - 如 Spring Cloud @LoadBalanced

具体的代码如下:

package org.learn.spring.dependency.injection.annotation;import org.springframework.beans.factory.annotation.Qualifier;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 用户组 注解 扩展 @Qualifier
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface UserGroup {
}
package org.learn.spring.dependency.injection;import org.learn.spring.dependency.injection.annotation.UserGroup;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;import java.util.Collection;// Qualifier 注解依赖注入
public class QualifierAnnotationDependencyInjectionDemo {@Autowiredprivate User user; // superUser -> primary@Autowired@Qualifier(value = "user") // 指定Bean 名称或者id注入private User nameUser;// 整体应用上下文存在4个 User类型的Bean:// superUser// user// user1 -> @Qualifier// user2 -> @Qualifier@Autowiredprivate Collection<User> allUsers; // 2 Bean superUser + user@Autowired@Qualifierprivate Collection<User> qualifiedUsers; // 2 Bean = user1 + user2 -> 4 Bean = user1 + user2 + user3 + user4@Autowired@UserGroupprivate Collection<User> groupedUsers; // 2 Bean = user3 + user4@Bean@Qualifier // 进行逻辑分组public User user1(){return createUser(7L);}@Bean@Qualifier // 进行逻辑分组public User user2(){return createUser(8L);}@Bean@UserGrouppublic User user3(){return createUser(9L);}@Bean@UserGrouppublic User user4(){return createUser(10L);}public static User createUser(Long id){User user = new User();user.setId(id);return user;}public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(QualifierAnnotationDependencyInjectionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 QualifierAnnotationDependencyInjectionDemo BeanQualifierAnnotationDependencyInjectionDemo demo = applicationContext.getBean(QualifierAnnotationDependencyInjectionDemo.class);// 期待输出superUser BeanSystem.out.println("demo.user = " + demo.user);// 期待输出user BeanSystem.out.println("demo.nameUser = " + demo.nameUser);// 期待输出2 Bean superUser + userSystem.out.println("demo.allUsers = " + demo.allUsers);// 期待输出2 Bean user1 user2System.out.println("demo.qualifiedUsers = " + demo.qualifiedUsers);// 期待输出2 Bean user3 user4System.out.println("demo.groupedUsers = " + demo.groupedUsers);// 显示的关闭spring应用上下文applicationContext.close();}
}

15.延迟依赖注入

使用 API ObjectFactory 延迟注入

  • 单一类型
  • 集合类型

使用 API ObjectProvider 延迟注入( 推荐)

  • 单一类型
  • 集合类型

具体的代码如下:

package org.learn.spring.dependency.injection;import org.learn.spring.dependency.injection.annotation.UserGroup;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;import java.util.Collection;
import java.util.Set;// ObjectProvider 实现延迟依赖注入
public class LazyAnnotationDependencyInjectionDemo {@Autowiredprivate User user; // 实时注入@Autowiredprivate ObjectProvider<User> userObjectProvider; // 延迟注入@Autowiredprivate ObjectFactory<Set<User>> usersObjectFactory;public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(LazyAnnotationDependencyInjectionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 LazyAnnotationDependencyInjectionDemo BeanLazyAnnotationDependencyInjectionDemo demo = applicationContext.getBean(LazyAnnotationDependencyInjectionDemo.class);// 期待输出superUser BeanSystem.out.println("demo.user = " + demo.user);// 期待输出superUser BeanSystem.out.println("demo.userObjectProvider = " + demo.userObjectProvider.getObject()); // 继承ObjectFactory中的方法// 期待输出superUser User BeanSystem.out.println("demo.usersObjectFactory = " + demo.usersObjectFactory.getObject());demo.userObjectProvider.stream().forEach(System.out::println);// 显示的关闭spring应用上下文applicationContext.close();}
}

16.依赖处理过程

基础知识

  • 入口 - DefaultListableBeanFactory#resolveDependency
  • 依赖描述符 - DependencyDescriptor
  • 自定绑定候选对象处理器 - AutowireCandidateResolver

先来简单的分析下对应的源码,具体的代码如下:

/*
*
descriptor ——依赖项的描述符(字段/方法/构造函数)
requestingBeanName – 声明给定依赖项的 bean 的名称
autowiredBeanNames – 应该将所有自动装配 bean 的名称(用于解析给定的依赖项)添加到的集合
typeConverter – 类型转换器
*/
@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;}
}

我们先来看第一个参数DependencyDescriptor依赖的描述符,我们先打开对应的代码,先看对应的属性,具体的如下:

public class DependencyDescriptor extends InjectionPoint implements Serializable {// 被注入的类、容器private final Class<?> declaringClass;// 注入的方法的名称@Nullableprivate String methodName;// 注入的方法的参数类型@Nullableprivate Class<?>[] parameterTypes;// 注入的参数的索引private int parameterIndex;// 注入的字段的名称@Nullableprivate String fieldName;// 是否是必须注入的 对应的@Autowired注解中的值private final boolean required;// 对应的是@Lazy注解中的值private final boolean eager;// 嵌入的层次private int nestingLevel = 1;// 包含的类@Nullableprivate Class<?> containingClass;// 泛型的内容,后面的内容会讲@Nullableprivate transient volatile ResolvableType resolvableType;// 类型的描述@Nullableprivate transient volatile TypeDescriptor typeDescriptor;}

上面只是简单的分析了一下,比较模糊,下面我们通过一个简单的例子和debug的方式来帮助我们更深层次的理解,具体的例子如下:

package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;import java.util.Set;// 注解实现延迟依赖注入处理过程
public class AnnotationDependencyInjectionResolutionDemo {@Autowired // 依赖查找(处理)private User user;  // DependencyDescriptor ->// 必须(required = true)// (eager = true) 实时注入// 通过类型(User.class)// 字段名称("user")// 是否是首要的(primary = true)public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 LazyAnnotationDependencyInjectionDemo BeanAnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);// 期待输出superUser BeanSystem.out.println("demo.user = " + demo.user);// 显示的关闭spring应用上下文applicationContext.close();}
}

我们在DefaultListableBeanFactory#resolveDependency方法中加入对应的断点,然后Debug,就可以看到如下的截图,看看我们之前猜测的DependencyDescriptor是否是对的,具体的内容如下:

我们继续拿出之前的代码,具体的如下:

@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {// 这儿是字段注入,所以这个方法直接返回descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());// descriptor.getDependencyType() 获取依赖的类型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;}
}

descriptor.getDependencyType()是获取依赖的类型,具体的内容如下:

public Class<?> getDependencyType() {// 这里的field 是等于userif (this.field != null) {// 这儿的层级是等于1,所以直接返回的userif (this.nestingLevel > 1) {Type type = this.field.getGenericType();for (int i = 2; i <= this.nestingLevel; i++) {if (type instanceof ParameterizedType) {Type[] args = ((ParameterizedType) type).getActualTypeArguments();type = args[args.length - 1];}}if (type instanceof Class) {return (Class<?>) type;}else if (type instanceof ParameterizedType) {Type arg = ((ParameterizedType) type).getRawType();if (arg instanceof Class) {return (Class<?>) arg;}}return Object.class;}else {// 直接返回userreturn this.field.getType();}}else {return obtainMethodParameter().getNestedParameterType();}}

由于descriptor.getDependencyType()返回的是user类型,所以上面的resolveDependency的四个if判断的类型都是不满足的,直接走最后一个判断。代码如下:

// 这个方法返回 null,后面再说
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
if (result == null) {result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;

然后会直接调用doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);方法,具体的内容如下:

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {// 只有多次嵌套的时候这儿才不会返回nullInjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {// 快捷方式这儿也是没有的,返回的是nullObject shortcut = descriptor.resolveShortcut(this);if (shortcut != null) {return shortcut;}// 这儿返回的是user类型Class<?> type = descriptor.getDependencyType();// 这儿返回的也是null,后面我们会讲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,也是nullObject multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}// 这儿方法中的beanName 等于的是 annotationDependencyInjectionResolutionDemo 也是被注入的beanName// type 是User.class// descriptor 是前面我们的DependencyDescriptor.classMap<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);}
}

这儿我们需要了解是findAutowireCandidates(beanName, type, descriptor);方法,具体的内容如下:

protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {// 这儿是查找对应的beanName// this DefaultListableBeanFactory// requiredType User.class// true 查找的时候包含非单例的Bean// descriptor.isEager() 是否是非延迟加载// 这儿返回的beanName 应该是两个 一个 user 一个是superUser// 这儿是有序的,这儿的顺序就是你定义的顺序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;}}}// 直接跳到这个地方// 这儿遍历两次,将刚刚找出来的beanName,然后找到对应的Class 添加到reslut中去for (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}// 这儿的长度是2,直接返回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;
}

上面的流程走完了,我们在回到原来的代码,具体的如下:

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {// 只有多次嵌套的时候这儿才不会返回nullInjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {// 快捷方式这儿也是没有的,返回的是nullObject shortcut = descriptor.resolveShortcut(this);if (shortcut != null) {return shortcut;}// 这儿返回的是user类型Class<?> type = descriptor.getDependencyType();// 这儿返回的也是null,后面我们会讲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,也是nullObject multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}// 这儿方法中的beanName 等于的是 annotationDependencyInjectionResolutionDemo 也是被注入的beanName// type 是User.class// descriptor 是前面我们的DependencyDescriptor.classMap<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);// 这个map的长度是2,这个判断是不会进的,继续往下走if (matchingBeans.isEmpty()) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;// 会走到这儿if (matchingBeans.size() > 1) {// 这儿会找到首要的Bean,就是PrimaryautowiredBeanName = 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;}}// 这儿找到了superUserinstanceCandidate = matchingBeans.get(autowiredBeanName);}else {// We have exactly one match.Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}// 添加到对应autowiredBeanNames 添加的内容是superUserif (autowiredBeanNames != null) {autowiredBeanNames.add(autowiredBeanName);}// superUser 直接getBean 这儿直接转成一个Bean对象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);}
}

上面的源码分析,是注入一个简单的,下面我们来分析下注入集合的。将原来的示例代码修改如下:

package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;import java.util.Collection;
import java.util.Map;
import java.util.Set;// 注解实现延迟依赖注入处理过程
public class AnnotationDependencyInjectionResolutionDemo {@Autowired // 依赖查找(处理)private User user;  // DependencyDescriptor ->// 必须(required = true)// (eager = true) 实时注入// 通过类型(User.class)// 字段名称("user")// 是否是首要的(primary = true)@Autowired // 集合类型的依赖注入private Map<String, User> users; // user superUserpublic static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 LazyAnnotationDependencyInjectionDemo BeanAnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);// 期待输出superUser BeanSystem.out.println("demo.user = " + demo.user);// 显示的关闭spring应用上下文applicationContext.close();}
}

前面的代码都是一样的,我们直接看如下的代码:

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {// 只有多次嵌套的时候这儿才不会返回nullInjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {// 快捷方式这儿也是没有的,返回的是nullObject shortcut = descriptor.resolveShortcut(this);if (shortcut != null) {return shortcut;}// 这儿返回的是user类型Class<?> type = descriptor.getDependencyType();// 这儿返回的也是null,后面我们会讲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;}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);}
}

这儿直接调用的resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);这个方法,具体的代码如下:

 @Nullableprivate Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {// 这儿的获取的类型是mapfinal Class<?> type = descriptor.getDependencyType();// 判断不满足 直接跳过if (descriptor instanceof StreamDependencyDescriptor) {Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}Stream<Object> stream = matchingBeans.keySet().stream().map(name -> descriptor.resolveCandidate(name, type, this)).filter(bean -> !(bean instanceof NullBean));if (((StreamDependencyDescriptor) descriptor).isOrdered()) {stream = stream.sorted(adaptOrderComparator(matchingBeans));}return stream;}// 判断不满足 直接跳过else if (type.isArray()) {Class<?> componentType = type.getComponentType();ResolvableType resolvableType = descriptor.getResolvableType();Class<?> resolvedArrayType = resolvableType.resolve(type);if (resolvedArrayType != type) {componentType = resolvableType.getComponentType().resolve();}if (componentType == null) {return null;}Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,new MultiElementDescriptor(descriptor));if (matchingBeans.isEmpty()) {return null;}if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);if (result instanceof Object[]) {Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);if (comparator != null) {Arrays.sort((Object[]) result, comparator);}}return result;}// 判断不满足 直接跳过else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();if (elementType == null) {return null;}Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,new MultiElementDescriptor(descriptor));if (matchingBeans.isEmpty()) {return null;}if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());Object result = converter.convertIfNecessary(matchingBeans.values(), type);if (result instanceof List) {Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);if (comparator != null) {((List<?>) result).sort(comparator);}}return result;}// 直接跳到这个地方else if (Map.class == type) {// 获取Map的类型ResolvableType mapType = descriptor.getResolvableType().asMap();// 获取 Map的key 的类型 String.classClass<?> keyType = mapType.resolveGeneric(0);// 判断不成立 继续if (String.class != keyType) {return null;}// 获取 Map的value的类型 User.classClass<?> valueType = mapType.resolveGeneric(1);// 判断不成立 继续if (valueType == null) {return null;}// 将这个value的类型调用前面我们讲过的方法 和前面的逻辑是一样的,进行查找,这个时候返回是user superUserMap<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,new MultiElementDescriptor(descriptor));// 这儿查找出来了,不会空,继续if (matchingBeans.isEmpty()) {return null;}// 这儿也不是空,直接将对应beanName添加到autowiredBeanNames 返回if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}return matchingBeans;}else {return null;}}

由于这儿返回不是null,所以doResolveDependency()也不会走接下来的逻辑,直接返回,这样就找到了。

还有OptionalObjectFactoryObjectProvider,Lazy的情况,我这儿就不讲了,感兴趣的可以去看看。需要注意的是如果是Lazy的话,返回的是代理的对象,只有在使用的时候,才会初始化。

17.@Autowired 注入

@Autowired 注入规则

  • 非静态字段
  • 非静态方法
  • 构造器

@Autowired 注入过程

  • 元信息解析
  • 依赖查找
  • 依赖注入( 字段、 方法)

前面的代码我们主要分析的是依赖的查找的过程,但是@Autowired 注入过程还有两个比较重要的过程,一个是元信息解析,还有一个是依赖的注入。这个时候我们需要通过idea的调用栈来得到这一部分的答案。主要调用的是AutowiredAnnotationBeanPostProcessor#AutowiredFieldElement#inject的方法,具体的代码如下:

     @Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {// 需要注入的filedField field = (Field) this.member;Object value;// 默认是false,直接跳过if (this.cached) {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}else {// 创建DependencyDescriptor 依赖描述DependencyDescriptor desc = new DependencyDescriptor(field, this.required);// 设置包含的类 AnnotationDependencyInjectionResolutionDemo.classdesc.setContainingClass(bean.getClass());// 装配的beanName 后面会进行查找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;}}}// 找到了,通过反射的方法创建对应的file,然后set进去。if (value != null) {ReflectionUtils.makeAccessible(field);field.set(bean, value);}}

这个时候我们需要通过对应的调用栈继续往上查找,先看到的是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition具体的代码如下:

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);
}

我们需要看findAutowiringMetadata(beanName, beanType, null);元数据的解析。代码的如下:

 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {// Fall back to class name as cache key, for backwards compatibility with custom callers.// 获取的 缓存的keyString cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());// Quick check on the concurrent map first, with minimal locking.// 从缓存中取值,第一次肯定为空InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {synchronized (this.injectionMetadataCache) {// 再次从缓存中取值,还是为空metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {if (metadata != null) {metadata.clear(pvs);}// 构建元数据metadata = buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;}
 private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;do {final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();// 通过递归的查找 @Autowired 的属性,直至查找Object.classReflectionUtils.doWithLocalFields(targetClass, field -> {// 查找对应的属性是否有 @Autowired 的注解MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {// 这儿我们也可以看出是不支持 static的属性if (Modifier.isStatic(field.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static fields: " + field);}return;}// 判断是否是requiredboolean required = determineRequiredStatus(ann);currElements.add(new AutowiredFieldElement(field, required));}});// 通过递归的查找 @Autowired 的方法,直至查找Object.classReflectionUtils.doWithLocalMethods(targetClass, method -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (Modifier.isStatic(method.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static methods: " + method);}return;}if (method.getParameterCount() == 0) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation should only be used on methods with parameters: " +method);}}boolean required = determineRequiredStatus(ann);PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new AutowiredMethodElement(method, required, pd));}});elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}

通过上面的分析,元信息解析是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition,依赖查找,依赖注入( 字段、 方法)是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties

18.@Inject 注入

@Inject 注入过程

  • 如果 JSR-330 存在于 ClassPath 中, 复用 AutowiredAnnotationBeanPostProcessor 实现

我们可以看下AutowiredAnnotationBeanPostProcessor,这个类可以处理的注解是@Value、@Autowired、@Inject,具体的如下:

 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.}}

那么是怎么去针对出现多个对应的注解查找呢?findAutowiredAnnotation(AccessibleObject ao)我们需要看的方法如下:

 @Nullableprivate MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {MergedAnnotations annotations = MergedAnnotations.from(ao);// autowiredAnnotationTypes 是LinkedHashSet是有序的,这儿的插入的属性是Autowired Value Inject// 所以如果一个字段或者方法上出现多个这个注解优先处理Autowired注解for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {MergedAnnotation<?> annotation = annotations.get(type);if (annotation.isPresent()) {return annotation;}}return null;}

这个时候我们简单的演示一个例子。具体的如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><parent><artifactId>learn-spring-core</artifactId><groupId>org.learn.spring</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>dependency-injection</artifactId><dependencies><dependency><groupId>${groupId}</groupId><artifactId>ioc-container-overview</artifactId><version>${version}</version><scope>compile</scope></dependency><!-- JSR 303 --><dependency><groupId>javax.inject</groupId><artifactId>javax.inject</artifactId><version>1</version></dependency></dependencies>
</project>
package org.learn.spring.dependency.injection;import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;import javax.inject.Inject;
import java.util.Collection;
import java.util.Map;
import java.util.Set;// 注解实现延迟依赖注入处理过程
public class AnnotationDependencyInjectionResolutionDemo {@Autowired // 依赖查找(处理)private User user;  // DependencyDescriptor ->// 必须(required = true)// (eager = true) 实时注入// 通过类型(User.class)// 字段名称("user")// 是否是首要的(primary = true)@Autowired // 集合类型的依赖注入private Map<String, User> users; // user superUser@Injectprivate User injectUser;public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 LazyAnnotationDependencyInjectionDemo BeanAnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);// 期待输出superUser BeanSystem.out.println("demo.injectUser = " + demo.injectUser);// 显示的关闭spring应用上下文applicationContext.close();}
}

19.Java通用注解注入原理

CommonAnnotationBeanPostProcessor

  • 注入注解

    • javax.xml.ws.WebServiceRef
    • javax.ejb.EJB
    • javax.annotation.Resource
  • 生命周期注解
    • javax.annotation.PostConstruct
    • javax.annotation.PreDestroy

其实CommonAnnotationBeanPostProcessor的处理和AutowiredAnnotationBeanPostProcessor的处理是差不多,这儿我们看下不同的地方,具体的如下:

先来看下处理的类型:

static {try {@SuppressWarnings("unchecked")Class<? extends Annotation> clazz = (Class<? extends Annotation>)ClassUtils.forName("javax.xml.ws.WebServiceRef", CommonAnnotationBeanPostProcessor.class.getClassLoader());webServiceRefClass = clazz;}catch (ClassNotFoundException ex) {webServiceRefClass = null;}try {@SuppressWarnings("unchecked")Class<? extends Annotation> clazz = (Class<? extends Annotation>)ClassUtils.forName("javax.ejb.EJB", CommonAnnotationBeanPostProcessor.class.getClassLoader());ejbRefClass = clazz;}catch (ClassNotFoundException ex) {ejbRefClass = null;}// @Resource 注解resourceAnnotationTypes.add(Resource.class);// @WebServiceRef 注解if (webServiceRefClass != null) {resourceAnnotationTypes.add(webServiceRefClass);}// @EJB 注解if (ejbRefClass != null) {resourceAnnotationTypes.add(ejbRefClass);}}
public CommonAnnotationBeanPostProcessor() {setOrder(Ordered.LOWEST_PRECEDENCE - 3);// @PostConstruct注解setInitAnnotationType(PostConstruct.class);// @PreDestroy 注解setDestroyAnnotationType(PreDestroy.class);// @WebServiceContext 注解ignoreResourceType("javax.xml.ws.WebServiceContext");}

然后就是元数据的解析,具体的如下:

@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {// 调用父类的postProcessMergedBeanDefinition的方法,主要的是处理生命周期的元数据super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);}

我们先来看看生命周期的元数据的处理,具体的如下:

 @Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {LifecycleMetadata metadata = findLifecycleMetadata(beanType);metadata.checkConfigMembers(beanDefinition);}
 private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {if (this.lifecycleMetadataCache == null) {// Happens after deserialization, during destruction...return buildLifecycleMetadata(clazz);}// Quick check on the concurrent map first, with minimal locking.LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);if (metadata == null) {synchronized (this.lifecycleMetadataCache) {metadata = this.lifecycleMetadataCache.get(clazz);if (metadata == null) {metadata = buildLifecycleMetadata(clazz);this.lifecycleMetadataCache.put(clazz, metadata);}return metadata;}}return metadata;}
 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<>();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));}

上面的代码熟悉嘛?和前面的AutowiredAnnotationBeanPostProcessor几乎是一样的,这儿我不做过多的赘述了。然后处理完了生命周期的函数,我们再来看看需要注入的数据的处理。具体的如下:

 private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {// Fall back to class name as cache key, for backwards compatibility with custom callers.String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());// Quick check on the concurrent map first, with minimal locking.InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {synchronized (this.injectionMetadataCache) {metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {if (metadata != null) {metadata.clear(pvs);}metadata = buildResourceMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;}
 private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;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));}}});ReflectionUtils.doWithLocalMethods(targetClass, method -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {if (Modifier.isStatic(method.getModifiers())) {throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");}if (method.getParameterCount() != 1) {throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);}PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));}else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {if (Modifier.isStatic(method.getModifiers())) {throw new IllegalStateException("@EJB annotation is not supported on static methods");}if (method.getParameterCount() != 1) {throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);}PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new EjbRefElement(method, bridgedMethod, pd));}else if (bridgedMethod.isAnnotationPresent(Resource.class)) {if (Modifier.isStatic(method.getModifiers())) {throw new IllegalStateException("@Resource annotation is not supported on static methods");}Class<?>[] paramTypes = method.getParameterTypes();if (paramTypes.length != 1) {throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);}if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new ResourceElement(method, bridgedMethod, pd));}}}});elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}

流程也是一样的,这儿也不做过多的赘述,我们再来看依赖查找和依赖的注入的流程,具体的如下:

 @Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);try {metadata.inject(bean, beanName, pvs);}catch (Throwable ex) {throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);}return pvs;}

流程是一样的,这儿也不做过多的赘述。我们需要了解的是生命周期的函数的处理。前面的已经生成对应的LifecycleMetadata那么在什么地方调用呢?

可以看到InitDestroyAnnotationBeanPostProcessor中的调用。具体的代码如下:

初始化的方法

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());try {metadata.invokeInitMethods(bean, beanName);}catch (InvocationTargetException ex) {throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());}catch (Throwable ex) {throw new BeanCreationException(beanName, "Failed to invoke init method", ex);}return bean;}

销毁的方法

 @Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());try {metadata.invokeDestroyMethods(bean, beanName);}catch (InvocationTargetException ex) {String msg = "Destroy method on bean with name '" + beanName + "' threw an exception";if (logger.isDebugEnabled()) {logger.warn(msg, ex.getTargetException());}else {logger.warn(msg + ": " + ex.getTargetException());}}catch (Throwable ex) {logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);}}

20.自定义依赖注入注解

基于 AutowiredAnnotationBeanPostProcessor 实现

自定义实现

  • 生命周期处理

    • InstantiationAwareBeanPostProcessor

    • MergedBeanDefinitionPostProcessor

  • 元数据

    • InjectedElement
    • InjectionMetadata

第一种方式可以通过元注解的方式,具体的如下:

package org.learn.spring.dependency.injection.annotation;import org.springframework.beans.factory.annotation.Autowired;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 自定义注解
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MyAutowired {boolean required() default true;
}
package org.learn.spring.dependency.injection;import org.learn.spring.dependency.injection.annotation.MyAutowired;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;import javax.inject.Inject;
import java.util.Collection;
import java.util.Map;
import java.util.Set;// 注解实现延迟依赖注入处理过程
public class AnnotationDependencyInjectionResolutionDemo {@Autowired // 依赖查找(处理)private User user;  // DependencyDescriptor ->// 必须(required = true)// (eager = true) 实时注入// 通过类型(User.class)// 字段名称("user")// 是否是首要的(primary = true)@Autowired // 集合类型的依赖注入private Map<String, User> users; // user superUser@MyAutowiredprivate User injectUser;public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 LazyAnnotationDependencyInjectionDemo BeanAnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);// 期待输出superUser BeanSystem.out.println("demo.injectUser = " + demo.injectUser);// 显示的关闭spring应用上下文applicationContext.close();}
}

通过自定义注解的方式,具体的代码如下:

package org.learn.spring.dependency.injection;import org.learn.spring.dependency.injection.annotation.InjectUser;
import org.learn.spring.dependency.injection.annotation.MyAutowired;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;import javax.inject.Inject;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;import static org.springframework.context.annotation.AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME;// 注解实现延迟依赖注入处理过程
public class AnnotationDependencyInjectionResolutionDemo {@Autowired // 依赖查找(处理)private User user;  // DependencyDescriptor ->// 必须(required = true)// (eager = true) 实时注入// 通过类型(User.class)// 字段名称("user")// 是否是首要的(primary = true)@Autowired // 集合类型的依赖注入private Map<String, User> users; // user superUser@Injectprivate User injectUser;@InjectUserprivate User myInjectUser;// 标记成static字段的话,会提前初始化@Bean(value = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)public static AutowiredAnnotationBeanPostProcessor beanPostProcessor(){AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();// @Autowired + @Inject + 新的注解@InjectUser处理Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(Arrays.asList(Autowired.class, Inject.class, InjectUser.class));autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);return autowiredAnnotationBeanPostProcessor;}public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 LazyAnnotationDependencyInjectionDemo BeanAnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);// 期待输出superUser BeanSystem.out.println("demo.user = " + demo.user);System.out.println("demo.injectUser = " + demo.injectUser);System.out.println("demo.myInjectUser = " + demo.myInjectUser);// 显示的关闭spring应用上下文applicationContext.close();}
}

但是上面的代码如果Inject.class如果不存在时候就会报错,不安全,那么我们可以改成如下的:

package org.learn.spring.dependency.injection;import org.learn.spring.dependency.injection.annotation.InjectUser;
import org.learn.spring.dependency.injection.annotation.MyAutowired;
import org.learn.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;import javax.inject.Inject;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;import static org.springframework.context.annotation.AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME;// 注解实现延迟依赖注入处理过程
public class AnnotationDependencyInjectionResolutionDemo {@Autowired // 依赖查找(处理)private User user;  // DependencyDescriptor ->// 必须(required = true)// (eager = true) 实时注入// 通过类型(User.class)// 字段名称("user")// 是否是首要的(primary = true)@Autowired // 集合类型的依赖注入private Map<String, User> users; // user superUser@Injectprivate User injectUser;@InjectUserprivate User myInjectUser;// 标记成static字段的话,会提前初始化/*@Bean(value = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)public static AutowiredAnnotationBeanPostProcessor beanPostProcessor(){AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();// @Autowired + @Inject + 新的注解@InjectUser处理Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(Arrays.asList(Autowired.class, Inject.class, InjectUser.class));autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);return autowiredAnnotationBeanPostProcessor;}*/// 新老注解同时存在@Bean@Order(Ordered.LOWEST_PRECEDENCE - 3)public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();autowiredAnnotationBeanPostProcessor.setAutowiredAnnotationType(InjectUser.class);return autowiredAnnotationBeanPostProcessor;}public static void main(String[] args) {// 创建BeanFactory的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration Class 配置类 -> Spring BeanapplicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";// 加载XML资源,解析并生成BeanDefinitionbeanDefinitionReader.loadBeanDefinitions(xmlResourcePath);// 启动应用上下文applicationContext.refresh();// 依赖查找 LazyAnnotationDependencyInjectionDemo BeanAnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);// 期待输出superUser BeanSystem.out.println("demo.user = " + demo.user);System.out.println("demo.injectUser = " + demo.injectUser);System.out.println("demo.myInjectUser = " + demo.myInjectUser);// 显示的关闭spring应用上下文applicationContext.close();}
}

21.面试题

有多少种依赖注入的方式?

  • 构造器注入
  • Setter 注入
  • 字段注入
  • 方法注入
  • 接口回调注入

你偏好构造器注入还是 Setter 注入?

两种依赖注入的方式均可使用, 如果是必须依赖的话, 那么推荐使用构造器注入, Setter 注入用于可选依赖。

万字博客带你全面剖析Spring的依赖注入相关推荐

  1. 万字博客带你了解Spring Framework 的全貌

    1.写在前面 我之前出过一个系列介绍的是spring的源码的系列,但是由于当时个人的水平有限,有些地方介绍的也是模棱两可的,打算重启这块内容,上次只是介绍其中的一部分,例如国际化,事件等等这块的源码都 ...

  2. Hive必须了解的技能有哪些?万字博客带你掌握Hive

    大家早上好,本人姓吴,如果觉得文章写得还行的话也可以叫我吴老师.欢迎大家跟我一起走进数据分析的世界,一起学习! 感兴趣的朋友可以关注我或者我的数据分析专栏,里面有许多优质的文章跟大家分享哦. 目录 推 ...

  3. 两万字博客带你了解zabbix

    一. 监控服务的概述 1.zabbix功能 1)实时查看服务状态 2)可以发送报警信息(邮件 短信 电话 微信) 3)可以进行数据分析(潜在风险或者对业务部门给出数据建议)->京东会推荐你经常浏 ...

  4. 速通C语言第一站 一篇博客带你初识C语言

    感谢佬们支持! 文章目录 前言 一.C语言的前世今生&&如何写C语言 二.初识C语言 1.  第一个C语言程序(万恶之源) 2.  数据类型 计算机中的单位 介绍各种类型 各数据类型的 ...

  5. Flutter基础篇(2)-- 老司机用一篇博客带你快速熟悉Dart语法

    版权声明:本文为博主原创文章,未经博主允许不得转载.https://www.jianshu.com/p/3d927a7bf020 转载请标明出处: https://www.jianshu.com/p/ ...

  6. spring的依赖注入 -------基于注解方式

    前言: 做了2年的软件,刚开始入行的时候,没有个目标基本上都是在摸索,技术看的我眼花缭乱,这个想学,那个也想学结果是对很多技术一知半解的,工作中才发现,我们要掌握的一门可以搞定快速开发搞定所有业务需求 ...

  7. factorybean 代理类不能按照类型注入_《Spring入门经典》:使用Spring进行依赖注入

    第二章:使用Spring进行依赖注入 重点:配置并使用Spring容器 使用不同类型的配置元数据来配置Spring容器 理解依赖解析 了解自动装配的优缺点 在容器中执行显式Bean查找 学习不同的Be ...

  8. 据说,80%的人没有真正理解了Spring的依赖注入

    前言 提起Spring,大家肯定不陌生,它是每一个Java开发者绕不过去的坎.Spring 框架为基于 java 的企业应用程序提供了一整套解决方案,方便开发人员在框架基础快速进行业务开发. 在官网中 ...

  9. Spring的依赖注入方法

    文章目录 Spring中依赖注入的方法 基于构造方法的注入 根据索引赋值 根据所属类型传值 根据所属类型传值(不推荐) 基于setter注入 基于接口的注入(不常用,这里不说明了) 拓展方式注入 P命 ...

最新文章

  1. 2018 GitHub最火技术趋势
  2. java基础(八) 深入解析常量池与装拆箱机制
  3. vue点击图片后复制图片url_简单漂亮的(图床工具)开源图片上传工具——PicGo...
  4. 执行apt-get命令提示没有该命令
  5. antd 刷新页面及后退时菜单栏高亮问题
  6. 根据选择计算Mask值
  7. 堆和栈区别 java_JAVA中堆和栈的区别
  8. 超级简洁的xml解析框架:TBXML
  9. JDBC——连接数据库
  10. vue-router配置
  11. nlp n-gram_NLP中的单词嵌入:一键编码和Skip-Gram神经网络
  12. blender源代码分析----第三方库的说明
  13. Linux驱动 | DS18B20驱动编程
  14. 冯诺依曼结构和现代计算机结构模型
  15. 微博图床php上传,微博图床 - shitalpig的个人空间 - OSCHINA - 中文开源技术交流社区...
  16. 【YOLOv3原文+翻译】YOLOv3:An Incremental Improvement
  17. 正则表达式的含义于简介
  18. ElasticSearch索引基本操作POST PUT GET DELETE
  19. 如何实现机器人自动拉微信群
  20. 【黑马程序员pink老师前端】JavaScript对象

热门文章

  1. IDEA在import时飘红的解决办法
  2. 计算机游戏有哪些基本特征,计算机玩游戏有哪些重要要求? ?
  3. 图片纯前端JS压缩的实现
  4. Android Studio NKD开发之 FFmpeg库的引入--简单播放器(主要验证是否正确引入ffmpeg库)
  5. python详解(2)——数据类型与变量
  6. 网易企业邮箱子邮箱发送邮件
  7. 2019智能手表推荐_智能手表什么牌子好,智能手表排行榜2020
  8. 2017年网易实习程序员面试题
  9. 将Qt QCheckBox 默认选中样式改为对号选中
  10. 1.3 C++常量 (Constants )