Spring基础篇——通过Java注解和XML配置装配bean

阅读目录

 


  自动化装配的确有很大的便利性,但是却并不能适用在所有的应用场景,比如需要装配的组件类不是由自己的应用程序维护,而是引用了第三方的类库,这个时候自动装配便无法实现,Spring 对此也提供了相应的解决方案,那就是通过显示的装配机制——Java 配置和 XML 配置的方式来实现 bean 的装配。

回到顶部

1 Java 配置类装配 bean

  我们还是借助上篇博文中的老司机开车的示例来讲解。Car 接口中有开车的 drive 方法,该接口有两个实现——QQCar 和 BenzCar

package spring.impl;

import spring.facade.Car;

public class QQCar implements Car {
@Override
public void drive() {
System.out.println(
"开 QQ 车");
}
}

  既然是通过 Java 代码来装配 bean, 那就是不是我们上一篇讲的通过组件扫描的方式来发现应用程序中的 bean 的自动装配机制了,而是需要我们自己通过配置类来声明我们的 bean。我们先通过 @Configuration 注解来创建一个 Spring 的配置类,该类中包含了 bean 的创建细节——

import org.springframework.context.annotation.Configuration;
import spring.facade.Car;
import spring.impl.QQCar;

/**

  • @Configuration 表明该类是 Spring 的一个配置类,该类中会包含应用上下文创建 bean 的具体细节

  • @Bean 告诉 Spring 该方法会返回一个要注册成为应用上下文中的 bean 的对象
    */
    @Configuration
    public class CarConfig {

    @Bean
    public Car laoSiJi() {
    return new QQCar();
    }
    }

  以上类中创建的 bean 实例默认情况下和方法名是一样的,我们也可以通过 @Bean 注解的 name 属性自定义 ID, 例如 @Bean(name = "chenbenbuyi") ,那么在获取 bean 的时候根据你自己定义的 ID 获取即可。接着我们测试——

package spring.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import spring.config.CarConfig;
import spring.facade.Car;

public class CarTest {
@Test
public void carTest() {
ApplicationContext context
= new AnnotationConfigApplicationContext(CarConfig.class);
//根据 ID 从容器容获取 bean
Car car = (Car) context.getBean("chenbenbuyi");
car.drive();
}
}

  以上测试能够成功输出,这就表明我们能够获取到 QQCar 的实例对象的,而这也是最简单的基于 Java 配置类来装配 bean 的示例了。但是你可能会说,明明是我们自己创建的 Car 的实例,怎么就成了 Spring 为我们创建的呢?好吧,我们把 @Bean 注解拿开,测试当然是无法通过,会抛 NoSuchBeanDefinitionException 异常。这里,你可能需要好好理解控制反转的思想了:因为现在对于 bean 创建的控制权我们是交给了 Spring 容器的,如果没有 @Bean 注解,方法就只是一个普通方法,方法体返回的实例对象就不会注册到应用上下文(容器)中,也就说,Spring 不会为我们管理该方法返回的实例对象,当我们在测试类中向容器伸手要对象的时候,自然就找不到。

  上述示例过于简单,现在,我们要更进一步,给简单的对象添加依赖,来完成稍微复杂一点的业务逻辑。车是需要老司机来开的,于是我们同上篇一样定义一个 Man 类,Man 的工作就是开车——

package spring.impl;

import spring.facade.Car;

public class Man {

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Car car;</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Man(Car car) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.car =<span style="color: rgba(0, 0, 0, 1)"> car;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> work() {
    car.drive();
}

}

  Car 的对象实例是通过构造器注入,而 Car 的实例对象在配置类中通过方法 laoSiJi() 返回, 所以我们在配置类中可以直接调用 laoSiJi 方法获取 bean 注入到 Man 的实例对象——

package spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.facade.Car;
import spring.impl.BenzCar;
import spring.impl.Man;

@Configuration
public class CarConfig {

@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Car laoSiJi() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BenzCar();
}

@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Man work() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Man(laoSiJi());
}

}

  测试类中通过上下文对象的 getBean("work") 方法就可以获取到 Man 的实例对象,从而完成对老司机开车的测试。或许,你会觉得,work 方法是通过调用 laoSiJi 方法才获取的 Car 的实例的,实际上并非如此。因为有了 @Bean 注解Spring 会拦截所有对该注解方法的调用,直接返回该方法创建的 bean,也即容器中的管理的 bean。也就是说,laoSiJi 方法返回的 bean 交给了 Spring 容器管理后,当其他地方需要实例对象的时候,是直接从容器中获取的第一次调用方法产生的实例对象,而不会重复的调用 laoSiJi 方法。我们可以如下测试——

package spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.facade.Car;
import spring.impl.BenzCar;
import spring.impl.Man;

@Configuration
public class CarConfig {

@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Car laoSiJi() {
    System.out.println(</span>"方法调用"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BenzCar();
}

@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Man work() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Man(laoSiJi());
}

@Bean   
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Man work2() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Man(laoSiJi());
}

}

  如上测试你会发现,虽然我定义了两个方法来获取 Man 实例,但是控制台只输出了一次调用打印,即证明方法只在最初返回 bean 的时候被调用了一次,而后的实例获取都是直接从容器中获取的。这也就是默认情况下 Spring 返回的实例都是单例的原因:一旦容器中注册了实例对象,应用程序需要的时候,就直接给予,不用重复创建。当然,很多情况下我们不会如上面的方式去引入依赖的 bean, 而可能会通过参数注入的方式,这样你就可以很灵活的使用不同的装配机制来满足对象之间的依赖关系,比如下面这种自动装配的方式给 Man 的实例注入依赖的 Car 对象——

package spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import spring.facade.Car;
import spring.impl.Man;

@Configuration
@ComponentScan("spring.impl")
public class CarConfig {

@Bean
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Man work(Car car) {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Man(car);
}

}

  当然,如果你喜欢去简就繁,也可以通过 XML 配置文件配置依赖的 bean。下面再来看看 XML 的方式如何装配 bean。

回到顶部

2 XML 配置文件装配 bean

  使用 XML 配置文件的方式装配 bean,首要的就是要创建一个基于 Spring 配置规范的 XML 文件,该配置文件以 <beans> 为根元素(相当于 Java 配置的 @Configuration 注解),包含一个或多个 <bean> 元素 (相当于配置类中 @Bean 注解)。针对上文的汽车示例,如果改成 XML 配置就是这样——

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">通过类的全限定名来声明要创建的bean</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.BenzCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</beans>

  然后,从基于 XML 的配置文件中加载上下文定义,我们就能根据 ID 获取到对应的 bean 了——

package spring.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.facade.Car;

public class CarTest {
@Test
public void carTest() {
ApplicationContext context
= new ClassPathXmlApplicationContext("resource/applicationContext.xml");
//XML 的方式如果没有明确给定 ID,默认 bean 的 ID 会根据类的全限定名来命名,以 #加计数序号的方式命名。
Car car = (Car)context.getBean("spring.impl.BenzCar#0");
car.drive();
}
}

  当然,示例中使用自动化的命名 ID 看起来逼格满满,但其实并不实用,如果需要引用 bean 的实例就有点操蛋了,实际应用中当然还是要借助 <bean> 的 id 属性来自定义命名。

  2.1 构造器注入

  给 <bean> 元素设置 id 属性,在构建另外的对象实例的时候,就可以很方便的引用,譬如上面基于 Java 的配置中的构造器注入,XML 中的同样这样实现——

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="car"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.BenzCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="man"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.Man"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">通过Man的构造器注入Car的实例对象</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg </span><span style="color: rgba(255, 0, 0, 1)">ref</span><span style="color: rgba(0, 0, 255, 1)">="car"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</beans>

  而有时候我们并不一定都是将对象的引用装配到依赖对象中,也可以简单的注入字面值——

package spring.impl;

import spring.facade.Car;

public class Man {

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Car car;
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String str;<br></span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Man(String str ,Car car) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.car =<span style="color: rgba(0, 0, 0, 1)"> car;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.str =<span style="color: rgba(0, 0, 0, 1)"> str;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> work() {
    System.out.println(str);
    car.drive();
}

}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="car"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.BenzCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="man"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.Man"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">分别注入字面值和对象的应用</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg </span><span style="color: rgba(255, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">="陈本布衣"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg </span><span style="color: rgba(255, 0, 0, 1)">ref</span><span style="color: rgba(0, 0, 255, 1)">="car"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</beans>

  接着,我们继续对已有代码做些改动,将注入的参数改为 Car 的 List 集合——

 public Man(List<Car> cars) {
        this.cars = cars;
 }

   那么配置文件就可以这样配置——

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="benzCar"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.BenzCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="qqCar"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.QQCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="man"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.Man"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">通过&lt;list&gt;子元素实现List集合对象的装配</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">ref </span><span style="color: rgba(255, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">="benzCar"</span><span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">ref </span><span style="color: rgba(255, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">="qqCar"</span><span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</beans>

  如果是需要注入集合中的字面值,写法如下——

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="benzCar"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.BenzCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="qqCar"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.QQCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="man"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.Man"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">通过&lt;list&gt;子元素实现List集合字面值的装配</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>这里直接填写字面值<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
            <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>陈本布衣<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</beans>

  我们可以采用同样的方式装配 Set 集合,只是Set 集合会忽略掉重复的值,而且顺序也不保证。此处不做演示。

  2.2 属性注入

  构造器注入是一种强依赖注入,而很多时候我们并不倾向于写那种依赖性太强的代码,而属性的 Setter 方法注入作为一种可选性依赖,在实际的开发中是应用得非常多的。上面 Man 类如果要通过属性注入的方式注入 Car 的实例,就该是这样子——

package spring.impl;

import spring.facade.Car;

public class Man {

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Car car;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setCar(Car car) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.car =<span style="color: rgba(0, 0, 0, 1)"> car;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> work() {
    car.drive();
}

}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="benzCar"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.BenzCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="qqCar"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.QQCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="man"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.Man"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">通过属性注入的方式注入Car的实例</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="car"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="benzCar"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</beans>

  以上示例中,XML 配置文件中属性注入的属性名必须要和 Java 类中 Setter 方法对应的属性名一致。而对于字面量的注入,和上面构造器的方式类似,只不过使用的元素名换成了 <property> 而已,下面仅做展示——

    <bean id="man" class="spring.impl.Man">
        <property name="str" value="字面量的注入"></property>
        <property name="list">
            <list>
                <value>集合的字面量注入 1</value>
                <value>集合的字面量注入 2</value>
            </list>
        </property>
    </bean>
<bean id="benzCar" class="spring.impl.BenzCar"></bean>
    <bean id="qqCar" class="spring.impl.QQCar"></bean>
    <bean id="man" class="spring.impl.Man">
        <!--属性注入的方式注入集合-->
        <property name="cars">
            <list>
                <ref bean="qqCar"></ref>
                <ref bean="benzCar"></ref>
            </list>
        </property>
    </bean>
回到顶部

3 三种装配方式的混合使用

   在同一个应用程序中,Spring 常见的这三种装配方式我们可能都会用到,而对于不同的装配方式,他们之间如何实现相互引用从而整合到一起的呢?我们先看看 Java 配置类的引用问题。试想如果 Java 配置类中的 bean 数量过多,我们可能会考虑拆分。在本文的示例中,Man 类实例的创建必须通过构造器注入 Car 的实例,如果把两个实例的产生分成两个配置类,那么在依赖注入的配置类中可以通过 @Import 注解引入被依赖的配置类——

package spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import spring.facade.Car;
import spring.impl.Man;

@Configuration
@Import(CarConfig.class) //通过 @Import 注解引入产生 Car 实例的配置类
public class ManConfig {
@Bean
public Man work(Car car) {
return new Man(car);
}
}

  但是如果 Car 的实例不是通过 Java 类配置的,而是通过 XML 方式配置的方式配置,我们只需通过 @ImportResource 注解将配置 bean 的 XML 文件引入即可,只不过这个时候要保证 XML 中被依赖的 bean 的 id 要和 Java 配置类中的形参保持一致——

package spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import spring.facade.Car;
import spring.impl.Man;

@Configuration
@ImportResource("classpath:resource/applicationContext.xml")
public class ManConfig {
@Bean
public Man work(Car car) {
return new Man(car);
}
}

   而如果 bean 是采用 XML 进行装配,如果需要装配的 bean 过多,我们当然还是会根据业务拆分成不同的配置文件,然后使用 <improt> 元素进行不同 XML 配置文件之间的引入,形如: <import resource="classpath:xxx.xml" /> ;而如果要在 XML 中引入 Java 配置,只需将 Java 配置类当成普通的 bean 在 XML 中进行声明即可,但是在测试的时候要注意开启组件扫描,因为加载 XML 配置的上下文对象只会加载 XML 配置文件中的 bean 定义,无法让基于 Java 配置类产生 bean 的装配机制自动生效——

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">开启组件扫描,在测试的时候配置类才能向容器中注册类中声明的bean</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="spring"</span><span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">XML中引入Java配置类:将配置类声明为bean</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="spring.config.CarConfig"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="man"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="spring.impl.Man"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg </span><span style="color: rgba(255, 0, 0, 1)">ref</span><span style="color: rgba(0, 0, 255, 1)">="laoSiJi"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">constructor-arg</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</beans>

  最后说一点,不管是 Java 配置还是 XML 配置,有个通常的做法就是创建一个比所有配置都更高层次的根配置类 / 文件,该配置不声明任何的 bean,只用来将多个配置组合在一起,从而让配置更易于维护和扩展。好了,以上便是两种 bean 的装配方式的简单讲解,如有纰漏,欢迎指正,不胜感激。