Spring装配bean的方式

本文详细介绍了Spring框架中bean的装配方式,包括自动化装配(基于构造器和setter注入)、Java配置文件中的显式装配以及XML配置文件的装配。重点讲解了如何通过各种方式创建并管理bean之间的依赖关系。
摘要由CSDN通过智能技术生成

spring装配bean的方式

bean是指经历了完整的spring bean生命周期并被spring容器管理的对象,bean是一个对象。

装配bean是指两个及以上的bean之间存在依赖关系,将其中一个bean注入到另一个bean中。

spring装配bean主要有三种类型:一种隐式装配和两种显式装配,即隐式的自动化装配、java代码显式装配和XML配置文件显式装配,经常用的是隐式装配。在项目中应该优先使用隐式的自动装配,其次使用在Java中进行装配,最后再使用在XML中进行装配。

每种装配类型都有两种实现方式:基于构造器注入和基于setter注入(即属性注入)。还有一些方式是根据这两种变化而来的,比如基于注解(如@Autowired和@Resource)的注入方式,底层是通过反射实现的,field.set(value,targetObject),是setter注入方式的变体。

下面使用CompactDisc(光盘CD)和CDPlayer(CD播放器)讲解如何通过这三种方式创建并装配bean。

1、自动化装配

1.1、创建bean(组件扫描)

package cn.spring.entity;
import org.springframework.stereotype.Component;
@Component
public class CompactDisc {
    private String title = "Sgt. Peppers's Longly Hearts";
    private String artist = "The Beatles";
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}

上面实现类上使用了@Component注解,该注解表明该实现类会作为组件类,告诉spring容器要为该类创建一个bean,spring会自动帮我们创建。不过组件扫描默认是不开启的,我们需要显式配置一下spring,使用@ComponentScan注解开启组件扫描,从而命令spring去寻找带有@Component注解的类,并为其创建bean。(补充:@Controller@Service@Repository注解与@Component注解的作用相同。)

1.2、创建配置类并开启组件扫描

package cn.spring.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "cn.spring")
public class CDPlayerConfig {
}

@ComponentScan注解能够在spring中开启组件扫描,该注解会使spring默认扫描配置类所在的包及其子包,可以明确设置组件扫描的基础包,查找带有@Component注解的类,在spring上下文中自动创建一个bean。

在注解出现之前,XML配置方式是Spring IoC容器的唯一配置方式。之前,我们将配置信息集中写在XML中,如今使用注解,配置信息的载体由XML文件转移到了Java类中。我们通常将用于存放配置信息的类的类名以“Config”结尾,比如AppDaoConfig.java、AppServiceConfig.java 等等。我们需要在用于指定配置信息的类上加上@Configuration注解,以明确指出该类是Bean配置的信息源。加上@Configuration注解的类就是配置类,该注解的作用就是告诉spring,配置类起到了与XML配置文件相同的作用,好处是不用写那么多复杂的配置文件了。spring应用上下文AnnotationConfigApplicationContext 将配置类中标注了@Bean注解的方法的返回值识别为Spring Bean,并注册到容器中,受IoC 容器管理。用@Configuration注解类,等价于XML中配置beans,用@Bean标注方法等价于XML中配置bean。AnnotationConfigApplicationContext 在解析配置类时,会将配置类自身注册为一个 Bean,因为 @Configuration 注解本身定义时被 @Component 标注了。因此可以说,一个 @Configuration 同时也是一个 @Component。

@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Component  
public @interface Configuration {  
String value() default "";  
} 

1.3、自动装配bean

package cn.spring.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer {
    @Autowired
    private CompactDisc cd;
    public void play(){
        cd.play();
    }
}

自动装配就是让spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在spring上下文中寻找匹配某个bean所需求的其他bean,并注入进来。可以使用@Autowired或@Resource注解实现自动装配。

1.4、测试

package cn.spring.test;
import cn.spring.config.CDPlayerConfig;
import cn.spring.entity.CDPlayer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class SpringBeanTest {
    //@Autowired
    @Resource
    private CDPlayer cdPlayer;
    @Test
    public void test() {
        cdPlayer.play();
    }
}

在测试类CDPlayerTest上使用了@RunWith(SpringJUnit4ClassRunner.class)注解,以便在测试开始的时候自动创建spring的应用上下文。

@RunWith : 运行器 

@RunWith(JUnit4.class)就是指用JUnit4来运行

@RunWith(SpringJUnit4ClassRunner.class),让测试运行于Spring测试环境

@RunWith(Suite.class)的话就是一套测试集合

在测试类上使用了@ContextConfiguration(classes=CDPlayerConfig.class)注解,该注解会告诉spring需要在CDPlayerConfig配置类中加载应用上下文ApplicationContext配置。如果不加该配置,会报如下异常:java.lang.IllegalStateException: Failed to load ApplicationContext

注意:在测试类中不能通过new的方式创建一个CDPlayer对象,因为通过new方式创建的对象不归spring容器管理,spring容器为我们创建的CDPlayer对象中注入了CompactDisc对象,但是我们没有用它。new方式创建的对象中的实例变量需要被初始化,默认初始值是零值,因此,在CDPlayer中得到的CompactDisc的值就是null,会报空指针异常。

或者使用下面的测试类

package cn.spring.test;
import cn.spring.config.CDPlayerConfig;
import cn.spring.entity.CDPlayer;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class SpringBeanTest {
    @Test
    public void test() {
        //加载java配置类获取Spring应用上下文
        ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
        CDPlayer cdPlayer = context.getBean(CDPlayer.class);
        cdPlayer.play();
    }
}

2java配置装配

package cn.spring.entity;
public class CompactDisc {
    private String title = "Sgt. Peppers's Longly Hearts";
    private String artist = "The Beatles";
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}
package cn.spring.entity;
public class CDPlayer {
    private CompactDisc cd;
    public void setCompactDisc(CompactDisc cd){
        this.cd = cd;
    }
    public void play(){
        cd.play();
    }
}
package cn.spring.config;
import cn.spring.entity.CDPlayer;
import cn.spring.entity.CompactDisc;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CDPlayerConfig {
    @Bean
    public CompactDisc getCompactDisc(){
        return new CompactDisc();
    }
    @Bean
    public CDPlayer getCDPlayer(CompactDisc cd){
        CDPlayer cdPlayer = new CDPlayer();
        cdPlayer.setCompactDisc(cd);
        return cdPlayer;
    }
}

getCompactDisc和getCDPlayer方法必须在同一个配置类中。@Bean注解会告诉spring这个方法将会返回一个对象,该对象要注册为spring应用上下文中的bean,方法体中包含了最终产生bean实例的逻辑。默认情况下,bean的ID与带有@Bean注解的方法名是一样的,在上例中,getCDPlayer方法得到的bean的名字就是getCDPlayer。可以通过name属性为bean指定一个名字,如@Bean(name="myCDPlayer"),在获取bean时就可以通过名字来获取,即context.getBean("myCDPlayer")。

package cn.spring.test;
import cn.spring.config.CDPlayerConfig;
import cn.spring.entity.CDPlayer;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class SpringBeanTest {
    @Test
    public void test() {
        //加载java配置类获取Spring应用上下文
        ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
        CDPlayer cdPlayer = context.getBean(CDPlayer.class);
        cdPlayer.play();
    }
}

3XML配置装配

package cn.spring.entity;
public class CompactDisc {
    private String title = "Sgt. Peppers's Longly Hearts";
    private String artist = "The Beatles";
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}
package cn.spring.entity;
public class CDPlayer {
    private CompactDisc cd;
    /*public CDPlayer(CompactDisc compactDisc) {
    }*/
    public void setCompactDist(CompactDisc cd) {
        this.cd = cd;
    }
    public void play(){
        cd.play();
    }
}

spring配置文件:

<?xml version="1.0" encoding="utf-8"?>
<!--引入约束-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置待创建对象的类-->
    <bean id="disc" class="cn.spring.entity.CompactDisc"/>
    <bean id="player" class="cn.spring.entity.CDPlayer">
        <!--使用setter方法注入,在CDPlayer类中需要创建CompactDisc属性的set方法-->
        <property name="compactDist" ref="disc"/>
        <!--使用构造方法注入,在CDPlayer类中需要创建含有CompactDisc参数的构造方法-->
        <!--<constructor-arg ref="disc"/>-->
    </bean>
</beans>

测试类:

package cn.spring.test;
import cn.spring.entity.CDPlayer;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringBeanTest {
    @Test
    public void test() {
        //加载xml配置文件获取Spring应用上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("app.xml");
        //根据Class类型获取bean
        CDPlayer cdPlayer = context.getBean(CDPlayer.class);
        //根据bean的名字获取bean
        //CDPlayer cdPlayer = (CDPlayer) context.getBean("player");
        cdPlayer.play();
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值