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);
        }
    }
posted @ 2023-01-03 23:22  生活咖啡  阅读(190)  评论(0编辑  收藏  举报