zoukankan      html  css  js  c++  java
  • Spring 基础入门(一)

    本文代码部分来自于《spring in action》,本文讲的是使用!!

    Spring 是为了解决什么

           一个框架的存在是为了解决某个问题的,那么Spring这个框架是为了解决什么问题呢?主要就是解耦,spring主要要把握两方面的知识,

    • DI(依赖注入 dependency injection) : 解耦, 方便测试
    • AOP(面向切面编程 aspect-oriented programming)

          关于 DI Ioc 和 AOP 可以先阅读这篇文章,本文讲的主要是使用。

    DI (依赖注入 depency injection)

         先看一个例子:

      1 //定义一个勇士类
      2 public class DamselRescuingKnight implements Knight {
      3 
      4 	private RescueDamselQuest quest;
      5 
      6 	//营救任务
      7 	public DamselRescuingKnight() {
      8 		this.quest = new RescueDamselQuest();
      9 	}
     10 
     11 	public void embarkOnQuest() {
     12 		quest.embark();
     13 	}
     14 }

          可以看到这里,勇士的 embarkOnQuest ( ) 方法执行的传入的特定的任务,那么当勇士需要执行其他任务的时候就无法进行了,于是Queue 应该做成一个接口.这样的好处是解耦合和方便测试

      1 public class BraveKnight implements Knight {
      2 	private Quest quest;
      3 
      4 	public BraveKnight(Quest quest) {
      5 		this.quest = quest;
      6 	}
      7 
      8 	public void embarkOnQuest() {
      9 		quest.embark();
     10 	}
     11 }
      1 public class SlayDragonQuest implements Quest {
      2 	private PrintStream stream;
      3 
      4 	public SlayDragonQuest(PrintStream stream) {
      5 		this.stream = stream;
      6 	}
      7 
      8 	public void embark() {
      9 		stream.println("Embarking on quest to slay the dragon!");
     10 	}
     11 }

         上面使用依赖注入并且在构造器解耦被称为构造器解耦。 在spring中如何组装这些组件呢?(将queue配置给knight)

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns="http://www.springframework.org/schema/beans"
      3 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4 	xsi:schemaLocation="http://www.springframework.org/schema/beans
      5 	http://www.springframework.org/schema/beans/spring-beans.xsd">
      6 
      7 	<bean id="knight" class="com.springinaction.knights.BraveKnight">
      8 		<constructor-arg ref="quest" />
      9 	</bean>
     10 
     11 	<bean id="quest" class="com.springinaction.knights.SlayDragonQuest">
     12 		<constructor-arg value="#{T(System).out}" />
     13 	</bean>
     14 </beans>

      依赖注入

            图一. 依赖注入会将所依赖的关系自动交给目标对象, 而不是让对象自己去获取依赖

    AOP(面向切面编程)

         加入一个勇士需要一个历史记录着纪录它的英雄事迹,那么

      1 public class Recorder {
      2 	private PrintStream stream;
      3 
      4 	public Recorder(PrintStream stream) {
      5 		this.stream = stream;
      6 	}
      7 
      8 	public void singBeforeQuest() {
      9 		stream.println("Fa la la, the knight is so brave!");
     10 	}
     11 
     12 	public void singAfterQuest() {
     13 		stream.println("Tee hee hee, the brave knight " +
     14 		"did embark on a quest!");
     15 	}
     16 }
      1 public class BraveKnight implements Knight {
      2 	private Quest quest;
      3 	private Recorder recorder;
      4 
      5 	public BraveKnight(Quest quest, Recorder recorder) {
      6 		this.quest = quest;
      7 		this.recorder= recorder;
      8 	}
      9 
     10 	public void embarkOnQuest() throws QuestException {
     11 		recorder.singBeforeQuest();
     12 		quest.embark();
     13 		recorder.singAfterQuest();
     14 	}
     15 }

         但是这样似乎有点不合常理,当我需要一名勇士时是否每次都要匹配以为记录者?假如记录着可以当我需要的时候出现那么就好了。使用spring的AOP 编程,

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns="http://www.springframework.org/schema/beans"
      3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4        xmlns:aop="http://www.springframework.org/schema/aop"
      5        xsi:schemaLocation="http://www.springframework.org/schema/aop
      6 http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
      7 http://www.springframework.org/schema/beans
      8 http://www.springframework.org/schema/beans/spring-beans.xsd">
      9 
     10     <bean id="knight" class="com.springinaction.knights.BraveKnight">
     11         <constructor-arg ref="quest"/>
     12     </bean>
     13 
     14     <bean id="quest" class="com.springinaction.knights.SlayDragonQuest">
     15         <constructor-arg value="#{T(System).out}"/>
     16     </bean>
     17 
     18     <bean id="minstrel" class="com.springinaction.knights.Recorder">
     19         <constructor-arg value="#{T(System).out}"/>
     20     </bean>
     21 
     22     <aop:config>
     23         <aop:aspect ref="recorder">
     24             <aop:pointcut id="embark"
     25                           expression="execution(* *.embarkOnQuest(..))"/>
     26             <aop:before pointcut-ref="embark"
     27                         method="singBeforeQuest"/>
     28             <aop:after pointcut-ref="embark"
     29                        method="singAfterQuest"/>
     30         </aop:aspect>
     31     </aop:config>
     32 </beans>
     33 

    Spring 容器

         spring容器是使用DI(依赖注入)去管理组成应用的组件,其中包括两大类,

    • Application Cotext
    • Bean Factories

    Bean Factories 主要是低水准的应用, 下面主要介绍application context,它包括

    • AnnotationConfigApplicationContext :从一个或多个java形式的class文件中加载一个spring 应用
    • AnnotationConfigWebApplicationContext  : 从一个或多个java形式的class文件中加载一个spring web应用
    • FileSystemXmlApplication : 加载一个上下文定义(context)从文件路径中的xml文件
    • XmlWebApplicationConte
    • ClassPathXmlApplication

    AnnotationConfigWebApplicationContext 和 XmlWebApplicationContext 我们使用比较多的

     

    装配组件

      三种方式

    • XML 形式
    • JavaConfig形式
    • 隐式的bean发现机制 和 自动装配

       三种方式的选择: 根据《spring in action》的描述,隐式的bean 发现和自动装配方式强与显式装配, 假若不得不显式装配,优先选择类型安全的java编码形式的,最后才是XML形式

    自动配置

    Spring从两个角度来实现自动化装配:(一个是生成独立的bean, 一个是将他们组装起来)

    • 组件扫描(component scanning) : Spring会自动发现应用上下文中所创建的bean。
    • 自动装配(autowiring) : Spring自动满足bean之间的依赖。

        @Component 属性表明这个类是个组件,并且告诉spring 因为为它创建一个been

      1 @Component
      2 public class SgtPeppers implements CompactDisc {
      3 	private String title = "Sgt. Pepper's Lonely Hearts Club Band";
      4 	private String artist = "The Beatles";
      5 
      6 	public void play() {
      7 		System.out.println("Playing " + title + " by " + artist);
      8 	}
      9 }
      1 @Configuration
      2 @ComponentScan
      3 public class CDPlayerConfig {
      4 
      5 }

         @ComponentScan 表示组件扫描,在这个包下的组件都会被扫描出来并且创建为been,而@Configuration 将会在下面讲到,同时上面也可以通过xml的形式创建

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns="http://www.springframework.org/schema/beans"
      3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4        xmlns:context="http://www.springframework.org/schema/context"
      5        xsi:schemaLocation="http://www.springframework.org/schema/beans
      6             http://www.springframework.org/schema/beans/spring-beans.xsd
      7             http://www.springframework.org/schema/context
      8             http://www.springframework.org/schema/context/spring-context.xsd">
      9     <context:component-scan base-package="soundsystem" />
     10 </beans>

          组件被scan 后会生成一个bean ,然后生成一个id,默认为类名,那么下面展示的如何自定义这个id的名字,和如何指定spring在特定的路径下进行扫描

      1   1 //组件命名
      2   2 @Component("lonelyHeartsClub")
      3   3 public class SgtPeppers implements CompactDisc {
      4   4 ...
      5   5 }
      6   6
      7   7 //扫描基本路径,多个基本路径
      8   8 @Configuration
      9   9 @ComponentScan(basePackages= {"soundsystem", "video"})
     10  10 public class CDPlayerConfig {}

         扫描基类下的所有类

      1 @Configuration
      2 @ComponentScan(basePackageClasses={CDPlayer.class, DVDPlayer.class})
      3 public class CDPlayerConfig {}

         扫描完了,下面展示如何自动装配,使用@Autowired 注解,spring会自动将bean 加载进来,但是当bean 不存在时,spring加载时会抛出错误,为了防止spring直接抛出错误,可以设置 required = false

      1 @Component
      2 public class CDPlayer implements MediaPlayer {
      3     private CompactDisc cd;
      4     @Autowired
      5     public CDPlayer(CompactDisc cd) {
      6         this.cd = cd;
      7     }
      8     public void play() {
      9         cd.play();
     10     }
     11 
     12     @Autowired(required=false)
     13     public OtherCDPlayer(CompactDisc cd) {
     14         this.cd = cd;
     15     }
     16 }

    JAVA 编码装配bean

          当我们需要使用到第三方库时,我们就不能使用自动装配机制,可以使用XML形式和JavaConfig的形式来进行显式装配,java编码比xml形式的重构更加友好,类型安全,更加强大。

      1 @Configuration
      2 public class CDPlayerConfig {
      3 }

        使用@Configuration 注解表明这个类通过javaConfig形式告知spring为它创建一个bean。另外加入我们调用一个方法,而方法返回值是个对象,我们希望这个对象被spring生成一个bean,这又怎么写呢?

      1 @Bean(name="lonelyHeartsClubBand")
      2 public CompactDisc sgtPeppers() {
      3 	return new SgtPeppers();
      4 }

        和上面自动扫描一样,我们创建了bean, 是时候把它们装配起来了,假如CDPlayer 这个对象依赖CompactDisc 这个对象,我们需要对它进行注入。上面的代码可以知道sgtPeppers( ) 方法可以获取一个bean对象。

      1 @Bean
      2 public CDPlayer cdPlayer() {
      3 	return new CDPlayer(sgtPeppers());
      4 }

        可以看到我们同样调用了sgtPeppers( ) 方法,使用了@Bean注解,这个需要注意的是spring创建的bean都会是单例,什么意思呢?

      1 @Bean
      2 public CDPlayer cdPlayer() {
      3 	return new CDPlayer(sgtPeppers());
      4 }
      5 @Bean
      6 public CDPlayer anotherCDPlayer() {
      7 	return new CDPlayer(sgtPeppers());
      8 }

         在sgtPeppers( )方法中即使我们使用new 一个新的对象,调用这两个方法返回的CDPlay( )却是相同的,都是spring 创建的bean对象。我们可以使用一个简单的方式写法。

      1 @Bean
      2 public CDPlayer cdPlayer(CompactDisc compactDisc) {
      3 	return new CDPlayer(compactDisc);
      4 }

    XML 方式装配bean

           使用XML 形式进行装配bean,

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns="http://www.springframework.org/schema/beans"
      3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4        xsi:schemaLocation="http://www.springframework.org/schema/beans
      5        http://www.springframework.org/schema/beans/spring-beans.xsd
      6        http://www.springframework.org/schema/context">
      7 
      8        <bean id="cdPlay" class="soundsystem.SgtPeppers">
      9 </beans>

            初始化bean构造器注入有两种方式

    • 使用<constructor-arg>
    • 使用c-命名空间在Spring 3.0

           下面使用的时第一种,ref是传入的引用,是某个bean 的id

      1 <bean id="cdPlayer" class="soundsystem.CDPlayer">
      2 	<constructor-arg ref="compactDisc" />
      3 </bean>

           如果存在下面的类

      1 public class BlankDisc implements CompactDisc {
      2         private String title;
      3         private String artist;
      4         public BlankDisc(String title, String artist) {
      5             this.title = title;
      6             this.artist = artist;
      7         }
      8         public void play() {
      9             System.out.println("Playing " + title + " by " + artist);
     10         }
     11     }

           那么构造器依赖注入就是

      1 <bean id="compactDisc" class="soundsystem.BlankDisc">
      2     <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band"/>
      3     <constructor-arg value="The Beatles"/>
      4 </bean>
      5 
      6 <!--下面是c-命名空间,下划线后加参数名字-->
      7 <bean id="compactDisc"
      8       class="soundsystem.BlankDisc"
      9       c:_title="Sgt. Pepper's Lonely Hearts Club Band"
     10       c:_artist="The Beatles" />
     11 
     12 <!--也可以这样子写-->
     13 <bean id="compactDisc"
     14       class="soundsystem.BlankDisc"
     15       c:_0="Sgt. Pepper's Lonely Hearts Club Band"
     16       c:_1="The Beatles" />
     17 

          如果构造参数中有List,或是set,要是set 的话,只需要改节点为<set>

      1 <bean id="compactDisc" class="soundsystem.BlankDisc">
      2     <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
      3     <constructor-arg value="The Beatles" />
      4     <constructor-arg>
      5         <list>
      6             <value>Sgt. Pepper's Lonely Hearts Club Band</value>
      7             <value>With a Little Help from My Friends</value>
      8             <value>Lucy in the Sky with Diamonds</value>
      9             <value>Getting Better</value>
     10             <value>Fixing a Hole</value>
     11             <!-- ...other tracks omitted for brevity... -->
     12         </list>
     13     </constructor-arg>
     14 </bean>

            如果使用c命名空间的构造器注入,必须向在开头声明命令空间

      1 
      2 <?xml version="1.0" encoding="UTF-8"?>
      3 <beans xmlns="http://www.springframework.org/schema/beans"
      4        xmlns:c="http://www.springframework.org/schema/c"
      5        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      6        xsi:schemaLocation="http://www.springframework.org/schema/beans
      7 http://www.springframework.org/schema/beans/spring-beans.xsd">
      8     ...
      9 </beans>

          下面是如何使用

    构造器注入

      1 <bean id="cdPlayer" class="soundsystem.CDPlayer"
      2 c:cd-ref="compactDisc" />

        

            假如一个类没有构造方法,需要对属性进行注入

      1 public class BlankDisc implements CompactDisc {
      2     private String title;
      3     private String artist;
      4     private List<String> tracks;
      5     public void setTitle(String title) {
      6         this.title = title;
      7     }
      8     public void setArtist(String artist) {
      9         this.artist = artist;
     10     }
     11 
     12     public void setTracks(List<String> tracks) {
     13         this.tracks = tracks;
     14     }
     15     public void play() {
     16         System.out.println("Playing " + title + " by " + artist);
     17         for (String track : tracks) {
     18             System.out.println("-Track: " + track);
     19         }
     20     }
     21 }
      1 <bean id="compactDisc"
      2       class="soundsystem.BlankDisc">
      3     <property name="title"
      4               value="Sgt. Pepper's Lonely Hearts Club Band" />
      5     <property name="artist" value="The Beatles" />
      6     <property name="tracks">
      7         <list>
      8             <value>Sgt. Pepper's Lonely Hearts Club Band</value>
      9             <value>With a Little Help from My Friends</value>
     10             <value>Lucy in the Sky with Diamonds</value>
     11             <value>Getting Better</value>
     12             <value>Fixing a Hole</value>
     13             <!-- ...other tracks omitted for brevity... -->
     14         </list>
     15     </property>
     16 </bean>
     17 

          和c-命名空间相同, p-命名空间用来标识属性注入的,但是需要注意的是p-命名空间不能注入List,只能用spring-util 命名空间对集合进行注入,同样,在使用命令空间时需要在xml开头声明

      1 xmlns:p="http://www.springframework.org/schema/p"
      2 xmlns:util="http://www.springframework.org/schema/util"
      1 <bean id="compactDisc"
      2       class="soundsystem.BlankDisc"
      3       p:title="Sgt. Pepper's Lonely Hearts Club Band"
      4       p:artist="The Beatles"
      5       p:tracks-ref="trackList" />
      1 <util:list id="trackList">
      2     <value>Sgt. Pepper's Lonely Hearts Club Band</value>
      3     <value>With a Little Help from My Friends</value>
      4     <value>Lucy in the Sky with Diamonds</value>
      5     <value>Getting Better</value>
      6     <value>Fixing a Hole</value>
      7     <!-- ...other tracks omitted for brevity... -->
      8 </util:list>

          即使当显示声明bean时,我们更趋向javaCofig 形式装配,但是有些时候XML 形式的才是最好的选择,spring允许两者混合使用,如下

    在javaCofig形式中引入xml配置

          加入存在以下图的依赖关系

    依赖

      1 @Configuration
      2 public class CDConfig {
      3     @Bean
      4     public CompactDisc compactDisc() {
      5         return new SgtPeppers();
      6     }
      7 }
      8 
      9 
     10 //我们直接使用 @Import 注解通过引入另外一个类,来装配bean,
     11 @Configuration
     12 @Import(CDConfig.class)
     13 public class CDPlayerConfig {
     14     @Bean
     15     public CDPlayer cdPlayer(CompactDisc compactDisc) {
     16         return new CDPlayer(compactDisc);
     17     }
     18 }
     19 
     20 
     21 //或是我们创建多一个类,直接引入两个类,来装配bean
     22 @Configuration
     23 @Import({CDPlayerConfig.class, CDConfig.class})
     24 public class SoundSystemConfig {
     25 }
     26 

            假如BlankDisc 是定义在XML 中,如何通过Java形式来进行装配,使用@ImportResource()注解

      1 <bean id="compactDisc"
      2       class="soundsystem.BlankDisc"
      3       c:_0="Sgt. Pepper's Lonely Hearts Club Band"
      4       c:_1="The Beatles">
      5     <constructor-arg>
      6         <list>
      7             <value>Sgt. Pepper's Lonely Hearts Club Band</value>
      8             <value>With a Little Help from My Friends</value>Importing and mixing configurations 61
      9             <value>Lucy in the Sky with Diamonds</value>
     10             <value>Getting Better</value>
     11             <value>Fixing a Hole</value>
     12             <!-- ...other tracks omitted for brevity... -->
     13         </list>
     14     </constructor-arg>
     15 </bean>
      1 @Configuration
      2 @Import(CDPlayerConfig.class)
      3 @ImportResource("classpath:cd-config.xml")
      4 public class SoundSystemConfig {
      5 }

          其中,classpath :cd-config.xml 表示xml的位置。假如需要从另外的XML 文件中引入一个bean

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns="http://www.springframework.org/schema/beans"
      3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4        xmlns:c="http://www.springframework.org/schema/c"
      5        xsi:schemaLocation="http://www.springframework.org/schema/beans
      6        http://www.springframework.org/schema/beans/spring-beans.xsd">
      7 
      8     <import resource="cd-config.xml" />
      9     <bean id="cdPlayer"
     10           class="soundsystem.CDPlayer"
     11           c:cd-ref="compactDisc" />
     12 </beans>
     13 

          从java形式装配引入到XML 中,直接使用bean

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns="http://www.springframework.org/schema/beans"
      3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4        xmlns:c="http://www.springframework.org/schema/c"
      5        xsi:schemaLocation="http://www.springframework.org/schema/beans
      6     http://www.springframework.org/schema/beans/spring-beans.xsd">
      7     <bean class="soundsystem.CDConfig" />
      8     <bean id="cdPlayer"
      9           class="soundsystem.CDPlayer"
     10           c:cd-ref="compactDisc" />
     11 </beans>

          当需要装配一个bean来自XML ,一个来自javaConfig,那么按照之前的想法就是将多一个更加高层次的类对两个bean进行装配。

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns="http://www.springframework.org/schema/beans"
      3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4        xmlns:c="http://www.springframework.org/schema/c"
      5        xsi:schemaLocation="http://www.springframework.org/schema/beans
      6        http://www.springframework.org/schema/beans/spring-beans.xsd">
      7     <bean class="soundsystem.CDConfig" />
      8     <import resource="cdplayer-config.xml" />
      9 </beans>

           好了,这一篇讲了bean 装配的问题,下一篇继续学习!加油

  • 相关阅读:
    HBase的compact分析
    HBase Rowkey的散列与预分区设计
    Zookeeper 快速理解
    oozie 入门
    Apache Storm内部原理分析
    Java ArrayList源码剖析
    Java HashSet和HashMap源码剖析
    初步掌握Yarn的架构及原理
    UML用例图总结
    UML类图几种关系的总结
  • 原文地址:https://www.cnblogs.com/Benjious/p/8445511.html
Copyright © 2011-2022 走看看