Spring依赖查找
Spring Framework提供了以下几种依赖查找Bean的方式
1. 按名称进行查找
按id和name查找都归属于此。具体的又会分为直接查找与间接查找的方式。
1.1 直接查找
以xml为例,新建父Maven项目工程,pom依赖如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring.version>5.2.2.RELEASE</spring.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
新建子module工程,便于代码管理,依赖如下:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
定义模型对象User,内容如下:
public class User {
private Long id;
private String name;
// Getter、Setter方法略
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
在resources目录下新建META-INF/spring-ioc-overview.xml文件,定义User对象。内容如下:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.vielat.spring.ioc.domain.User">
<property name="id" value="1" />
<property name="name" value="Michael" />
</bean>
</beans>
依赖查找测试类如下:
public class DependencyLookupDemo {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/spring-ioc-overview.xml");
lookupByName(beanFactory);
}
private static void lookupByName(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("直接查找:" + user);
}
}
1.2 间接查找
间接查找也被称之为延迟查找,不是直接通过查找目标对象的方式获取Bean,而是通过ObjectFactory进行获取。
在META-INF/spring-ioc-overview.xml文件中新增如下配置:
...
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user" />
</bean>
测试类代码如下:
private static void lookupByObjectFactory(BeanFactory beanFactory) {
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
User user = objectFactory.getObject();
System.out.println("间接查找:" + user);
}
2.按类型进行查找
从Spring 3.0开始,支持JDK 5,而JDK 5引入了泛型的概念,因此可以直接传入Class
2.1 查找单个对象
private static void lookupByType(BeanFactory beanFactory){
User user = beanFactory.getBean(User.class);
System.out.println("直接查找:" + user);
}
2.2 查找集合对象
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> userMap = listableBeanFactory.getBeansOfType(User.class);
System.out.println("查找到的集合对象:" + userMap);
}
}
2.3 间接(延迟)查找
在BeanFactory中直接提供了一种获取ObjectProvider对象的方式,如下:
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
ObjectProvider也是一个接口,提供了getObject()方法。通过此种方式获取User对象,
private static void lookupByObjectProvider(BeanFactory beanFactory) {
ObjectFactory<User> objectFactory = beanFactory.getBeanProvider(User.class);
System.out.println("ObjectFactory:" + objectFactory);
System.out.println(objectFactory.getObject());
}
运行后结果如下:
ObjectFactory:org.springframework.beans.factory.support.DefaultListableBeanFactory$1@7791a895
User{id=1, name='Michael'}
3. 结合名称和类型进行查询
在BeanFactory接口中提供了此种查找Bean的方式,如下:
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
案例略
4. 根据注解的方式进行查询
在ListableBeanFactory接口中提供了getBeansWithAnnotation()方法。案例如下:
定义的注解如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Candidate {
}
新增一个实体类AdminUser
public class AdminUser extends User {
private String address;
// Getter、Setter方法略
@Override
public String toString() {
return "AdminUser{" +
"address='" + address + '\'' +
"} " + super.toString();
}
}
在META-INF/spring-ioc-overview.xml配置文件中新增此类配置
<bean id="adminUser" class="com.vielat.spring.ioc.domain.AdminUser" parent="user">
<property name="address" value="广州"/>
</bean>
在根据类型获取当个对象时,就会报错:
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.vielat.spring.ioc.domain.User' available: expected single matching bean but found 2: user,adminUser
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1180)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:416)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1126)
at com.vielat.spring.ioc.overview.DependencyLookupDemo.lookupByType(DependencyLookupDemo.java:43)
一种做法就是在其中一个Bean的配置上加primary="true"的配置;一种就是在对象上增加注解,通过注解的方式来获取:
增加配置的方式:
<bean id="adminUser" class="com.vielat.spring.ioc.domain.AdminUser" parent="user" primary="true">
<property name="address" value="广州"/>
</bean>
增加注解
@Candidate
public class AdminUser extends User {
......
}
测试类如下:
private static void lookupByAnnotation(BeanFactory beanFactory){
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String,Object> beanMap = listableBeanFactory.getBeansWithAnnotation(Candidate.class);
System.out.println("根据注解查找:" + beanMap);
}
}