美文网首页
Spring小记(3):Spring的bean的装配(基础)

Spring小记(3):Spring的bean的装配(基础)

作者: 夜玉龙 | 来源:发表于2018-05-08 10:02 被阅读13次

    在spring中,对象无需自己查找或创建与其所关联的其他对象,容器负责把需要相互协作的对象引用赋予各个对象,容器的这种创建对象之间协作关系的行为被称为装配,也被成为依赖注入(DI),依赖注入有3种方案可供选用,如下

    1、在XML中进行显式的配置
    2、在Java中进行显式的配置
    3、隐式的bean发现机制和自动装配
    
    隐式的bean发现机制和自动装配

    看下面一个实例
    1、创建一个接口

    public interface CompactDisc {
        void play();
    }
    

    2、添加这个接口的实现,注意我们在类的头部添加了@Component的注解,表明这个类是一个组件

    @Component
    public class SgtPeppers implements CompactDisc {
        private String title = "Sgt. Pepper's Lonely Hearts Club Band";
        private String artist = "The Beatles";
    
    
        @Override
        public void play() {
            System.out.println("Playing " + title + " by " + artist);
        }
    }
    

    3、添加对这个组件的配置,这个类里面什么东西都没有,只有类的头部有两个注解,分别为@Configuration和@ComponentScan,其中@ComponentScan注解表明会对这个包中的包含@Component的类进行扫描

    @Configuration
    @ComponentScan
    public class CDPlayConfig {
    }
    

    4、编写一个简单的JUnit例子

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = CDPlayConfig.class)
    public class CDPlayConfigTest {
    
        @Autowired
        private CompactDisc cd;
    
        @Test
        public void cdShouldNotBeNull(){
            assertNotNull(cd);
        }
    } 
    

    在上面的JUnit的例子中,类的头部包含了@RunWith注解和@ContextConfiguration注解,其中RunWith中的SpringJUnit4ClassRunner.class将会为我们创建Spring应用的上下文,ContextConfiguration中的classes = CDPlayConfig.class则表明我们将在CDPlayConfig中加载配置
    运行,会发现JUnit的测试是通过的

    为被装配的组件命名

    Spring应用的上下文中的所有的bean都会有一个ID来标识自己,假如我们不强制指定,那么Spring会根据类名为其指定一个ID,一般会把类的第一个字母小写来作为ID,比如上面的SgtPeppers,那么这个bean的ID就是sgtPeppers,我们也可以自己指定ID,有两种方式,分别如下
    第一种是在Component里面直接写上ID

    @Component("lonelyHeartClub")
    public class SgtPeppers implements CompactDisc {
        ...
    }
    

    第二种是使用DI的参数@Named注解,如下

    @Named("lonelyHeartClub")
    public class SgtPeppers implements CompactDisc {
        ...
    }
    

    不过推荐使用第一种

    对于@ComponentScan的注解,假如我们不指定扫描的包,那么就会扫描配置类当前所在的包,我们也可以指定我们需要进行扫描的包,如下

    @ComponentScan(basePackages = "com.fan.soundsystem")
    public class CDPlayConfig {
    }
    

    不过也可以使用类所在包作为扫描的包,如下

    @Configuration
    @ComponentScan(basePackageClasses = CDPlayConfig.class)
    public class CDPlayConfig {
    }
    

    @Autowired是自动装配注解,表明会在上下文中搜索bean并装配到参数之中,假如没有匹配的bean,那么就会抛出异常,为了避免异常的发生,我们可以设置@Autowired的required属性为false。我们同样可以使用@Inject来替代@Autowired,如下

    @Inject
    public void setCompactDisc(CompactDisc cd){
        this.cd = cd;
    }
    
    通过JavaConfig进行bean的装配

    1、我们针对CompactDisc创建一个新的实现

    @Component
    public class Revolver implements CompactDisc {
        private String title = "Revolver";
        private String artist = "The Beatles";
    
        @Override
        public void play() {
            System.out.println("Playing " + title + " by " + artist);
        }
    }
    

    2、然后我们把CDPlayConfig 中的@ComponentScan注解移除,并添加我们自己写的注入,需要注意的是,假如我们有两个创建CompactDisc 的方法被增加了注解@bean,那么我们将得不到一个正确的结果,如下面注释的部分不能出现

    @Configuration
    public class CDPlayerConfig1 {
    //    @Bean
    //    public CompactDisc sgtCompactDisc(){
    //        return new SgtPeppers();
    //    }
        @Bean
        public CompactDisc randomBeatlesCD(){
            int choice = (int) Math.floor(Math.random() * 4);
            if(choice == 0){
                return new SgtPeppers();
            }else {
                return new Revolver();
            }
        }
    
        @Bean
        public CDPlayer cdPlayer(){
            return new CDPlayer(randomBeatlesCD());
        }
    }
    

    3、对JUnit的实例做一下简单的修改

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = CDPlayerConfig1.class)
    public class CDPlayConfigTest {
    //    @Rule
    //    public final StandardOutputStreamLog log = new
    
        @Autowired
        private CDPlayer cd;
    
        @Test
        public void cdShouldNotBeNull(){
            assertNotNull(cd.getCompactDisc());
        }
    

    这样同样能够取得相同的效果

    通过XML进行bean的装配

    基于XML装配bean的方法配置风格有两种,分别为

    <constructor-arg>元素
    使用Spring3.0所引入的c空间
    

    使用<constructor-arg>的配置文件如下所示

    <?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="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
           <bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer">
                  <constructor-arg ref="compactDisc"/>
           </bean>
    </beans>
    

    我们可以通过这种方式来获取bean

    使用c命名空间的方式配置如下

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:c="http://www.springframework.org/schema/c"
           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="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
           <bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer" c:cd-ref="compactDisc"/>
    </beans>
    

    我们为上面的配置编写一个测试方法,如下

    public class Main {
        public static void main(String[] args){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
            CDPlayer cd = context.getBean(CDPlayer.class);
            cd.getCompactDisc().play();
            context.close();
        }
    }
    

    c命名空间相比之下更加的灵活
    我们有时候需要将字面量注入到bean之中,我们在这种情况下该怎么做呢?
    如下,我们先创建一个类,并不设置任何注解

    public class BlankDisc implements CompactDisc {
        private String title;
        private String artist;
        private List<String> tracks;
    
        public BlankDisc(String title,String artist,List<String> tracks){
            this.title = title;
            this.artist = artist;
            this.tracks = tracks;
        }
    
    
        @Override
        public void play() {
            System.out.println("Playing " + title + " by " + artist);
            for(String track : tracks)
                System.out.println("-Track:" + track);
        }
    }
    

    然后利用配置给这个bean进行配置

    <bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
                  <constructor-arg value="Sgt. Pepper's Lonely Hearts Clubs Band"/>
                  <constructor-arg value="The Beatles"/>
                  <constructor-arg>
                         <list>
                                <value>Sgt. Peper's Lonely Hearts Club Band</value>
                                <value>Fixing a Hole</value>
                         </list>
                  </constructor-arg>
           </bean>
    

    和引用注入一样,我们同样可以使用c命名空间进行注入,如下

    <bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
                   c:title="Sgt. Pepper's Hearts Club Band"
                   c:artist="The Beatles"
                   c:tracks-ref="trackList"/>
    

    以上都是构造器注入的方法,有时候我们需要对属性进行注入,那么我们可以使用下面这种方式,首先我们需要改造一下BlankDisc的写法

    public class BlankDisc implements CompactDisc {
        private String title;
        private String artist;
        private List<String> tracks;
    
    //    public BlankDisc(String title,String artist,List<String> tracks){
    //        this.title = title;
    //        this.artist = artist;
    //        this.tracks = tracks;
    //    }
    
        public void setTitle(String title){this.title = title;}
        public void setArtist(String artist){this.artist = artist;}
        public void setTracks(List<String> tracks){this.tracks = tracks;}
    
    
        @Override
        public void play() {
            System.out.println("Playing " + title + " by " + artist);
            for(String track : tracks)
                System.out.println("-Track:" + track);
        }
    }
    

    注意其中的构造器必须注释掉,否则会出错,然后我们对配置文件进行编写

    <bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
                  <property name="title" value="Sgt. Pepper's Lonely Hearts Club Band"/>
                  <property name="artist" value="The Beatles"/>
                  <property name="tracks">
                         <list>
                                <value>Getting Better</value>
                                <value>Fixing a Hole</value>
                         </list>
                  </property>
           </bean>
    

    同样,我们还可以使用p空间进行配置,看下面

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:c="http://www.springframework.org/schema/c"
           xmlns:util="http://www.springframework.org/schema/util"
           xmlns:p="http://www.springframework.org/schema/p"
           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
                                http://www.springframework.org/schema/util
                                http://www.springframework.org/schema/util/spring-util.xsd">
    
           <bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
           
           <util:list id="trackList">
                  <value>Getting Better</value>
                  <value>Fixing a Hole</value>
           </util:list>
           <bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
                 p:title="Sgt. Pepper's Lonely Hearts Club Band"
                 p:artist="The Beatles"
                 p:tracks-ref="trackList"/>
    </beans>
    
    混合配置

    在通常的使用中,我们不仅可以使用上面3中方式的任何一种,而且我们还可以将各种方式进行组合使用,常见的做法是在JavaConfig中引用XML和在XML中引用JavaConfig,那么我们应该怎么做才能达到这一点呢

    JavaConfig中引用XML

    假如我们在一个测试单元中同事使用CDPlayer和BlankDisc,那么我们可以对CDPlayerConfig1 增加对BlankDisc的配置,如下所示

    @Configuration
    @ImportResource("classpath:springConfig.xml")
    public class CDPlayerConfig1 {
    //    @Bean
    //    public CompactDisc sgtCompactDisc(){
    //        return new SgtPeppers();
    //    }
        @Bean
        public CompactDisc randomBeatlesCD(){
            int choice = (int) Math.floor(Math.random() * 4);
            if(choice == 0){
                return new SgtPeppers();
            }else {
                return new Revolver();
            }
        }
    
        @Bean
        public CDPlayer cdPlayer(){
            return new CDPlayer(randomBeatlesCD());
        }
    }
    

    我们再修改一下测试单元的代码,如下

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = CDPlayerConfig1.class)
    public class CDPlayConfigTest {
    //    @Rule
    //    public final StandardOutputStreamLog log = new
    
        @Autowired
        private CDPlayer cd;
    
        @Autowired
        private BlankDisc bd;
    
        @Test
        public void cdShouldNotBeNull(){
            assertNotNull(cd.getCompactDisc());
            assertNotNull(bd);
        }
    } 
    

    运行并查看运行的结果,如下所示

    XML中引用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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
           <import resource="springConfig.xml"/>
           <bean class="com.fan.soundsystem.CDPlayerConfig1"/>
    </beans>
    

    再编写测试文件,如下

    public static void main(String[] args){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("TotalConfig.xml");
            AnnotationConfigApplicationContext context1 = new AnnotationConfigApplicationContext(CDPlayerConfig1.class);
            BlankDisc bd = context.getBean(BlankDisc.class);
            CDPlayer cdPlayer1 = context1.getBean(CDPlayer.class);
    //        CDPlayer cdPlayer = context1.getBean(CDPlayer.class);
            cdPlayer1.play();
            bd.play();
            context.close();
        }
    

    运行并查看结果

    相关文章

      网友评论

          本文标题:Spring小记(3):Spring的bean的装配(基础)

          本文链接:https://www.haomeiwen.com/subject/dqukfxtx.html