zoukankan      html  css  js  c++  java
  • spring装配bean

    概述

    spring 的核心依赖注入:创建应用对象之间协作关系的行为称为装配(wiring),他有以下几种方式:

    • 自动装配(结合注解)
    • Java中显示的配置
    • 在xml中显示的配置

    这三个方案,选哪一个都是可以的,能用自动配置的就有自动配置,对于一些框架的配置我们不能修改别人的源码,必要的xml显示配置也是必要的,而且我们也可以三个方案同时使用,一些Bean自动装配,一些Bean Java配置,一些Bean xml配置。 对于显示配置,多少有些不方便还是自动装配最简便,所以我们先讲第一个自动化配置

    创建项目

    我们首先新建一个meavn项目,我这里用的是idea,推荐大家使用,超爽的开发工具。 添加spring 和 test需要的依赖

     <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>3.2.0.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>3.2.0.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>3.2.0.RELEASE</version>
          <type>jar</type>
        </dependency>
    

    源码均在github上可以获取,地址会在文末给出,欢迎加Start

    自动化配置

    创建bean

    spring实现自动装配的方式: 通过组建扫描发现应用上下文所创建的bean并通过自动装配创建bean的依赖关系。

    1. 组件扫描 component-scan
    2. 自动装配 Autowire

    在当今社会中,交通工具有多种多样,比如公交车、火车、飞机等。人们可以乘坐不同的司机驾驶的不同交通工具来出行。为了演示spring的实例,我们先建立Car接口:

    /**
     * author yalunwang
     * 车抽象接口
     */
    public interface Car {
        void notice();
    }
    

    其中notice方法代表车到站提醒。这样任意的交通工具都可实现接口Car,代码降低耦合。 这里我们先定义一个BusCar(公交车):

    /**
     * author yalunwang
     * 公交车
     */
    @Component
    public class BusCar implements Car {
        private String carName="浦东25";
    
        @Override
        public void notice() {
            System.out.println(this.carName+"南京西路到了");
        }
    }
    

    @Component注解会告诉spring此类需要spring 创建该bean注册到 ioc容器中。因为组件扫描默认是不开启的,所以我们需要开启扫描,这样spring才会去寻找带有@Component的类并创建该bean。spring创建bean的时候都会给定一个ID,BusCar类的ID默认为busCar,会把类名的第一个变为小写。如果想指定ID为bus的可以这样写:@Component(value = "bus")或@Component("bus")。]

    告知spring开启自动扫描有两种办法:

    1. 在xml里配置
    2. 在javaconfig里配置

    首先来看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"
           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">
           <context:component-scan base-package="com.yalunwang.autowiring"></context:component-scan>
    </beans>
    

    <context:component-scan>元素就是开启自动扫描,其中的base-package是告诉spring扫描com.yalunwang.autowiring包以及其下的所有子包中带有@Component注解的类,并为之创建。

    我们再来看在java配置类里如何配置:

    @Configuration
    @ComponentScan(basePackages = "com.yalunwang.autowiring")
    public class PeopleCarConfig {
    }
    

    @ComponentScan与xml中的 <context:component-scan>起到相同的作用。其中如果不加basePackages ,即表示以此配置类所在的包。

    我们可以在单元测试里测试一下:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = PeopleCarConfig.class)
    public class TestCar {
        @Autowired
        private BusCar busCar;
        @Test
        public void testCar()
        {
            System.out.println(busCar);
        }
    }
    

    结果输出: com.yalunwang.autowiring.BusCar@1c3d5104

    • @RunWith(SpringJUnit4ClassRunner.class) 会自动创建spring上下文
    • @ContextConfiguration 加载配置
    • @Autowired 注入同类型的实例

    从结果中我们可以看出BusCar被spring创建。我们的自动扫描成功了。

    自动装配

    自动装配就是让spring自动将bean依赖的其他bean注入进去。我们可以使用@Autowired,在上文中的单元测试中我们刚刚使用了。为了演示自动装配我们再新建一个People接口用来抽象人类。

    /**
     * author yalunwang
     * 人类抽象接口
     */
    public interface People {
        void drive();
    }
    

    drive代表驾驶。 我们再创建一个Man来实现此接口。

    /**
     * author yalunwang
     * 男人
     */
    @Component
    public class Man implements People {
        private String userName ="小明";
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        @Autowired
        private Car car;
    
        @Override
    
        public void drive() {
            //System.out.println("driver");
            System.out.println("男司机:" + this.userName);
            car.notice();
        }
    }
    

    drive:要想使车可以跑起来我们需要一个司机,司机驾驶车辆,并提醒乘客到达哪一站了。 所以我们的Man bean现在依赖于Car bean,这时我们再car字段添加注解@Autowired就会自动将Carbean注入进来。

    这里注入的方式有很多种可以放到构造器,set方法,字段、其他方法。

        @Autowired
        private Car car;
    
        
        private Car car1;
        //构造器注入
        @Autowired
        public Man(Car car) {
            this.car1=car;
        }
    
    
        private Car car2;
    
        public Car getCar2() {
            return car2;
        }
        //set方法注入
        @Autowired
        public void setCar2(Car car2) {
            this.car2 = car2;
        }
    

    下面我来验证一下

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = PeopleCarConfig.class)
    public class TestPeople {
        @Autowired
        private People people;
        @Test
        public void test() {
            people.drive();
        }
    
    }
    

    输出:

    男司机:小明
    浦东25路南京西路到了
    

    这里可以看出我们的自动装配是通过了。自动扫描配置Bean先告一段落。

    Java代码中配置

    javaconfig类需要添加@@Configuration 注解,要在显示的配置bean我们需要使用@Bean注解

    @Configuration
    public class PeopleCarConfig {
      
        @Bean
        public Car busCar()
        {
            return new  BusCar();
        }
    }
    

    @Bean注解会告诉spring这个方法将返回一个一个对象,并且要注册到spring上下文中。方法体力包含了最终产生bean实例的逻辑。Bean的ID默认是方法的名字,可以通过 @Bean(name="busCar")指定自定义的名字。

    装配

    我们知道人需要开车,Man依赖Car,那么我们如何将car注入到man中呢。

    @Bean(name="man")
    public People man()
    {
        return new Man( busCar());
    }
    

    这样通过使用一个Car类型的实例对象BusCar的构造器构建Man实例,这里需要注意的是busCar()并非实际的方法调用,因为这个方法上加了@Bean注解,spring会拦截对他的调用并直接返回该方法所创建的bean。 我们可以做个实验:

    @Configuration
    public class PeopleCarConfig {
        private int i=1;
        @Bean
        public Car busCar()
        {
            i=i+1;
            System.out.println(i);
            return new  BusCar();
        }
        @Bean(name="man")
        public People man()
        {
            return new Man( busCar());
        }
        @Bean(name="woman")
        public People woman()
        {
            return new Woman( busCar());
        }
    }
    

    输出:

    2
    buscar构造函数
    男司机:小明
    浦东25路南京西路到了
    女司机:小红
    浦东25路南京西路到了
    

    从这里就可以看出来 busCar()并不会真正的调用,而是直接返回spring创建的bean. 我们也可以通过另外一种方法来注入:

    我们再创建一个Woman

    public class Woman implements People {
        private Car car;
        public Woman(Car car){
            this.car=car;
        }
        private String userName ="小红";
        @Override
        public void drive() {
            System.out.println("女司机:" + this.userName);
            car.notice();
        }
    }
    
      public People woman(Car car)
        {
            return new Woman( car);
        }
    

    这里woman()方法加了一个Car参数,这里会自动装配一个Car类型的实现类实例。需要注意的是这里Car类型的bean可以通过xml 自动配置 javaconfig配置来进行配置。所以这种方式是最佳的注入方式。 以上我们使用的构造器的方式,其实我们也可以通过set方式等其他任意java方式去创建。

    xml配置

    在javaconfig中配置bean需要加@Configuration,xml配置对应的需要创建一个spring的xml规范文件。取名spring-test.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">
    
    </beans>
    
    

    我们来配置一个bean

     <bean class="com.yalunwang.xmlconfig.BusCar" />
    

    这个<bean> 配置相当于javaconfig中的@Bean,这时bean的id默认为完全限定名com.yalunwang.xmlconfig.BusCar#0 我们可以指定id: busCar

    <bean id="busCar" class="com.yalunwang.xmlconfig.BusCar" />
    

    这时spring创建busCar 的时候回自动调用busCar的默认构造函数。

    下面我们来看在xml如何里装配

    装配bean

    1. 构造器方式
    <bean id="man" class="com.yalunwang.xmlconfig.Man" >
         <constructor-arg ref="busCar"/>
    </bean>
    

    这样就会在创建man实例的时候调用有参构造器,将id为busCar的bean实例注入进去。 我们也可以注入非引用类型即字面值:

     <bean id="busCar" class="com.yalunwang.xmlconfig.BusCar" >
                  <constructor-arg name="carName" value="浦东2"></constructor-arg>
    </bean>
    

    xml还支持多种类型的注入,例如list.大家都知道公交车有很多的站点所以我们新增一个字段stationList用来存放站点列表。 我们也可以注入list类型

     <bean id="busCar" class="com.yalunwang.xmlconfig.BusCar" >
            <constructor-arg name="carName" value="浦东2"></constructor-arg>
             <constructor-arg name="stationList">
                     <list>
                            <value>高科中路</value>
                            <value>宜山路</value>
                            <value>桂林路</value>
                     </list>
                </constructor-arg>
     </bean>
    
    

    同样的我们也可以使用<set> <map> <array>等来装配。

    我们编写测试类来测试一下:

    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring-test.xml"})
    public class Test {
        @Autowired
        private Car car;
        @org.junit.Test
        public void testBusCar()
        {
            car.notice();
            car.printStationList();
        }
         @Autowired
        private People people;
        @org.junit.Test
        public void testPeople()
        {
            people.drive();
        }
    }
    
    

    两个方法的输出分别是

    浦东2路南京西路到了
    站名:高科中路
    站名:宜山路
    站名:桂林路
    
    男司机:小明
    浦东2路南京西路到了
    
    

    下面来看属性注入

    1. 属性注入

    属注入是<property>元素

    为了演示属性注入我们先把man注释掉,以避免我们再单元测试类中使用@AutoWired注解报错(因为有两个People的实例bean,后面文章会介绍这个问题)

     <!--<bean id="man" class="com.yalunwang.xmlconfig.Man" >-->
                  <!--<constructor-arg name="car" ref="busCar"/>-->
           <!--</bean>-->
           <bean id="woman" class="com.yalunwang.xmlconfig.Woman" >
                  <property name="car" ref="busCar"></property>
           </bean>
    

    它会引用id为busCar的bean通过setCar()方法注入到car属性中。

    这时我们在运行testPeople输出

    女司机:小红
    浦东2路南京西路到了
    

    同样的属性也像构造函数方式注入一样可以注入字面值 <list><set>等类型的值。

     <bean id="woman" class="com.yalunwang.xmlconfig.Woman" >
                 <property name="car" ref="busCar"></property>
                 <property name="userName" value="韩梅梅"></property>
                 <property name="certificateList" >
                        <list>
                               <value>驾驶证</value>
                               <value>身份证</value>
                        </list>
                 </property>
          </bean>
    

    我们再次测试:

    女司机:韩梅梅
    浦东2路南京西路到了
    证书:驾驶证
    证书:身份证
    

    总结

    以上就是spring中的三种装配Bean的方式,这里只是将最核心也是最基本的内容展示出来了,关于spring中更高级的装配我们将在后面文章讲解。

    博客中的源码地址

    github地址:https://github.com/yalunwang/java-clump

    努力学习,每天进步一点点。加油
  • 相关阅读:
    MySQL数据库的常用命令
    MySQL数据库的概念
    Linux磁盘管理
    linux账号与权限管理
    安装及管理程序
    vi编辑器+常用命令
    centos7下部署elasticsearch7.2集群--Elastic Stack之一
    打开virt-manager界面显示方格乱码
    Rabbitmq之修改日志和数据存放路径
    Rabbitmq之Memory
  • 原文地址:https://www.cnblogs.com/yalunwang/p/8065307.html
Copyright © 2011-2022 走看看