springIoCAndDI

来源:互联网 发布:蒙泰5.0软件官方下载 编辑:程序博客网 时间:2024/06/05 02:50

一、       Introduction

Spring是一个轻量级java开源框架,兴起于2003年,由Rod.J创建。Spring提供了一种方法管理java应用的业务对象。Rod.J的《Expert one on one J2EE design anddevelopment》和《Expertone-on-one J2EE Development without EJB》催生了spring。Spring致力于J2EE各层的解决方案,可以与已有的框架无缝整合。

二、       初步搭建开发环境及IoC

(一)            新建好web工程后,导入基本jar包。

Core,bean,context,expression。

(二)            导入日志包和添加log4j的日志配置文件。

Logging,log4j

(三)            配置核心配置文件

1.        核心配置文件的理论依据—IOC控制反转思想

在分析前,设定类是java面向对象编程中的一个单元。不论是传统的三层框架处理业务或者仅仅是在java程序中创建类、使用类时,由于实例对象都是由使用这个对象的类创建的,那么在具有一定规模的程序系统中,作为独立单元的类之间以及独立的模块之间很容易形成高耦合的现象,带来的结果就是维护困难。高耦合不可完全避免,但是需要最大限度的降低,优化耦合。分析传统的程序过程,不难发现,很频繁的,独立的类或者模块之间会通过创建异己的类或模块的对象形成大量的耦合,专业上称,这种耦合为内容耦合的一种表现。内容耦合带来的维护成本很高,一旦被使用的类或者模块有更改,那么与其相关的类或者模块都可能会受到影响,如果工程很大,那么维护难度随之提高。一般,在软件工程中,需要尽量避免出现内容耦合。

而spring框架,自然需要解决这个问题,一部分,也是为了解决这个问题而生。面向对象编程,对象必须要创建,但是如果对象被需要使用它的单元来创建,就产生高内容耦合的问题。所以,是否可以即创建了对象,但是又不能让使用者来创建,而且使用者却可以使用这些对象。问题的关键就在于不能让使用者创建对象,将创建对象的权利交给与工程的业务弱关联的某种什么来创建。一定程度上,工厂模式体现了这一思路,但是没有从本质上解决这个问题。毕竟,工厂类本身也是一个类或者模块。大概在20世纪80年代末,产生出了IOC的想法,后来形成了明朗的IoC设计模式或者IoC思想理论。IoC,一般翻译为控制反转。大意即,将创建的控制权交出,而反转得到创建控制权的东西,称为容器。与工厂模式相比,在降低耦合度上,IoC进步的地方在于,彻底将控制权脱离出类或者模块,由一种略具抽象意义的容器来掌权。Spring就是这样的一种容器,类似的容器还有Avalon,JBoss,PicoContainer,HiveMind等,这样,所有的对象都通过容器来创建和管理,可以认为spring拥有一个生产和管理对象的工厂。具体实施中,是将创建的过程在xml文件中完成。Xml就是这个容器的实现形式。这个就是核心配置文件的理论来源。

在底层实现中,对象在xml配置文件中定义,然后通过java的反射编程,根据xml中的类名生成相应的对象。通过xml配置文件的方法,与工厂模式相比,将工厂与对象独立开来,进一步降低了工程内部的耦合度,降低了维护难度。

2.        建立applicationContext.xml

既然是xml文件,就需要schema。这些,spring官方都已提供好。

例如,关于JavaBean的约束。

<?xml version="1.0"encoding="UTF-8"?>

<beansxmlns="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。

<?xmlversion="1.0"encoding="UTF-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">

   <!--

      bean:spring创建的类的对象的组件。

      class:需要管理的类的类名(全路径名),也可以采用spring的别名机制处理。

      id或者name:使用组件创建的对象的标识。name可以使用一些特殊符号,现在一般使用id

    -->

    <beanid="test1"class="com.edu.ioc.test1.Test1"></bean>

</beans>

3.        使用bean组件创建的对象

ApplicationContext接口

org.springframework.context
Interface ApplicationContext

All Superinterfaces:

ApplicationEventPublisher,BeanFactory,HierarchicalBeanFactory,ListableBeanFactory,MessageSource,ResourceLoader,ResourcePatternResolver

All Known Subinterfaces:

ConfigurableApplicationContext,ConfigurablePortletApplicationContext,ConfigurableWebApplicationContext,WebApplicationContext

All Known Implementing Classes:

AbstractApplicationContext,AbstractRefreshableApplicationContext,AbstractRefreshableConfigApplicationContext,AbstractRefreshablePortletApplicationContext,AbstractRefreshableWebApplicationContext,AbstractXmlApplicationContext,ClassPathXmlApplicationContext,FileSystemXmlApplicationContext,GenericApplicationContext,GenericWebApplicationContext,ResourceAdapterApplicationContext,StaticApplicationContext,StaticPortletApplicationContext,StaticWebApplicationContext,XmlPortletApplicationContext,XmlWebApplicationContext

public interface ApplicationContext
extends ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver

Centralinterface to provide configuration for an application. This is read-only whilethe application is running, but may be reloaded if the implementation supportsthis.

AnApplicationContext provides:

1,Bean factory methods for accessingapplication components. Inherited fromListableBeanFactory.

2,The ability to load file resources in ageneric fashion. Inherited from theResourceLoaderinterface.

3,The ability to publish events to registeredlisteners. Inherited from theApplicationEventPublisherinterface.

4,The ability to resolve messages, supportinginternationalization. Inherited from theMessageSourceinterface.

Inheritance from a parent context. Definitionsin a descendant context will always take priority. This means, for example,that a single parent context can be used by an entire web application, whileeach servlet has its own child context that is independent of that of any otherservlet.

In additionto standard BeanFactorylifecycle capabilities, ApplicationContext implementations detect and invokeApplicationContextAwarebeans as well asResourceLoaderAware,ApplicationEventPublisherAwareandMessageSourceAwarebeans.

作者:Rod Johnson, Juergen Hoeller

另请参见: ConfigurableApplicationContext,BeanFactory,ResourceLoader

1)        较常用的方法,通过多态,创建ClassPathXmlApplicationContext的对象。

          Create a new ClassPathXmlApplicationContext, loading the definitions from the given XML file and automatically refreshing the context.

ClassPathXmlApplicationContext(String[] configLocations)
          Create a new ClassPathXmlApplicationContext, loading the definitions from the given XML files and automatically refreshing the context.

也可以传参数为配置文件的名称字符串的数组。

调用ClassPathXmlApplicationContext的父类AbstractApplicationContext的getBean方法,得到bean组件的对象。

 Object

getBean(String name)
          Return an instance, which may be shared or independent, of the specified bean.

<T> T

getBean(String name,Class<T> requiredType)
          Return an instance, which may be shared or independent, of the specified bean.

 Object

getBean(String name,Object... args)
          Return an instance, which may be shared or independent, of the specified bean.

例子:

public class Test1 {

   public voidtest1(){

      System.out.println("我是bean组件创建的对象。");

   }

}

另一个.java文件

public class Test2 {

   @Test

   public voidtestBean(){

      //使用应用上下文接口,加载核心配置文件,使用bean组件创建对象。

      ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");

      Test1 t1=(Test1)ac.getBean("test1");

      t1.test1();

   }

}

降低耦合的体现,在bean组件中,类名在bean中声明,而在使用对象中,通过id值使用。相当于id作为中介值,传递类名和使用对象,如果使用的对象需要改变,也就是类名需要改变,只要在xml的bean组件中,修改类名即可,这样只需一处改动,就可以通过这个id中介传递到所有使用这个类的对象的地方,降低了耦合。

2)        不常用的方法,创建FileSystemXmlApplicationContext的对象。与ClassPathXmlApplicationContext的差别是。这里的路径参数为绝对路径。

ApplicationContext ac=new FileSystemXmlApplicationContext("e:\\applicationContext.xml");

3)        两种获得bean的方式

A.       通过id/name的值,如上。一般使用这种方式。

B.       通过类名。如:getBean(Test1.class);

通过类名来获得bean,难以解决相同类名冲突的问题,而且不利于解耦和扩展。所以,一般不推荐使用。

三、       关于装配bean的方式

(一)            无参构造器的方式

1.        创建需要装配bean的类,如Test1.java。

2.        在spring核心配置文件applicationContext.xml中给类Test1配置bean。

3.        使用应用上下文,加载核心配置文件,通过getBean方法获得需要使用的bean。

例子见:二(三)3.1)

(二)            静态工厂的方法

1.        创建两个需要从工厂实例出的类,如Car.java和Bus.java。

2.        创建一个工厂用于获取类的实例对象,如VehicleFactory.java,工厂中需要有静态的getVehicle的方法。

3.        在xml中配置需要工厂“生产”的类的bean。

格式如:

<bean id=”…” class=”….” factory-method=”…”>

         <! -- 配置静态工厂方法的参数 -- >

         <constructor-argvalue=”…” />

         <!-- 配置通过setter方法注入出产的类的属性 -- >

         <propertyname=”…” value=”….” />

</bean>

4.        例子

public interface Vehicle {

   public voidgo();

}

----------------------------------------------------------------------------------------------------------

public class Bus implementsVehicle{

   private Stringname;

 

   public voidsetName(String name){

      this.name =name;

   }

   public voidgo(){

      System.out.println(name+"大大大");

   }

}

----------------------------------------------------------------------------------------------------------

public class Car implementsVehicle{

   //用于setter注入的属性

   private Stringname;

   public voidsetName(String name){

      this.name =name;

   }

   public voidgo(){

      System.out.println(name+"跑得快");

   }

}

----------------------------------------------------------------------------------------------------------

public class VehicleFactory {

   public staticVehicle getVehicle(Stringname){

      if("car".equalsIgnoreCase(name)){

         return new Car();

      }else{

         return new Bus();

      }

   }

}

----------------------------------------------------------------------------------------------------------

public class TestVehicle {

   @Test

   public voidtestVehicle(){

      ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");

      Vehicle vehicle1=(Vehicle)ac.getBean("car");

      vehicle1.go();

      Vehicle vehicle2=(Vehicle)ac.getBean("bus");

      vehicle2.go();

   }

}

----------------------------------------------------------------------------------------------------------

    <!-- 配置VehiclegetVehicle方法,来生产Car -->

    <beanid="car"class="com.edu.ioc.test1.VehicleFactory"factory-method="getVehicle">

       <!-- 配置工厂方法的参数 -->

       <constructor-argvalue="car"></constructor-arg>

       <!-- 配置产品的setter注入属性 -->

       <propertyname="name"value="小轿车"/>

    </bean>

    <!-- 配置VehiclegetVehicle方法,来生产Bus -->

    <beanid="bus"class="com.edu.ioc.test1.VehicleFactory"factory-method="getVehicle">

       <!-- 配置工厂方法的参数 -->

       <constructor-argvalue="bus"></constructor-arg>

       <!-- 配置产品的setter注入属性 -->

       <propertyname="name"value="公交车"/>

    </bean>

(三)            实例工厂的方法

1.        创建两个需要从工厂实例出的类,如Car.java和Bus.java。

2.        创建一个工厂用于获取类的实例对象,如VehicleFactory.java,工厂中需要有getVehicle的方法。与静态工厂相比,这里的方法不是静态的。

3.        在xml中先配置工厂类的bean,再配置需要工厂“生产”的类的bean。

注意,配置产品的bean时,要声明工厂是那个bean:

<bean id=”…” factory-bean=”….” factory-method=”…”>

         <! -- 配置静态工厂方法的参数 -- >

         <constructor-argvalue=”…” />

         <!-- 配置通过setter方法注入出产的类的属性 -- >

         <propertyname=”…” value=”….” />

</bean>

4.        例子

public interface Vehicle {

   public voidgo();

}

----------------------------------------------------------------------------------------------------------

public class Bus implementsVehicle{

   private Stringname;

 

   public voidsetName(String name){

      this.name =name;

   }

   public voidgo(){

      System.out.println(name+"大大大");

   }

}

----------------------------------------------------------------------------------------------------------

public class Car implementsVehicle{

   //用于setter注入的属性

   private Stringname;

   public voidsetName(String name){

      this.name =name;

   }

   public voidgo(){

      System.out.println(name+"跑得快");

   }

}

----------------------------------------------------------------------------------------------------------

public class VehicleFactoryInstance {

   public VehiclegetVehicle(Stringname){

      if("car".equalsIgnoreCase(name)){

         return new Car();

      }else{

         return new Bus();

      }

   }

}

----------------------------------------------------------------------------------------------------------

public class TestVehicle {

   @Test

   public voidtestVehicleInstance(){

      ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext2.xml");

      Vehicle vehicle1=(Vehicle)ac.getBean("car");

      vehicle1.go();

      Vehicle vehicle2=(Vehicle)ac.getBean("bus");

      vehicle2.go();

   }

}

----------------------------------------------------------------------------------------------------------

    <!-- 配置工厂的bean -->

    <beanid="vehicleFactory"class="com.edu.ioc.test1.VehicleFactoryInstance"/>

    <!-- 配置VehiclegetVehicle方法,来生产Car -->

    <beanid="car"factory-bean="vehicleFactory"factory-method="getVehicle">

       <!-- 配置工厂方法的参数 -->

       <constructor-argvalue="car"></constructor-arg>

       <!-- 配置产品的setter注入属性 -->

       <propertyname="name"value="小轿车"/>

    </bean>

    <!-- 配置VehiclegetVehicle方法,来生产Bus -->

    <beanid="bus"factory-bean="vehicleFactory"factory-method="getVehicle">

       <!-- 配置工厂方法的参数 -->

       <constructor-argvalue="bus"></constructor-arg>

       <!-- 配置产品的setter注入属性 -->

       <propertyname="name"value="公交车"/>

    </bean>

(四)            FactoryBean方式

FactoryBean是一个用于“生产Bean的工厂”的bean组件接口。

1.        创建个性化工厂实现FactoryBean接口。

2.        配置factorybean工厂要创建的bean。

3.        例子

 

public class MyFactory implements FactoryBean<Car>{

   public Car getObject()throws Exception {

      return new Car();

   }

   public Class<?> getObjectType() {

      return null;

   }

   public booleanisSingleton() {

      return false;

   }

}

    <!-- 通过工厂组件直接装配bean,与通过静态工厂,不需要声明factory-method,与实例工厂相比,不需要声明factory-bean,因为这个类本身就实现自factorybean,其实就是一个工厂组件,可以直接生产bean-->

    <beanid="carbean"class="com.edu.ioc.test1.MyFactory">

    </bean>

(五)            Bean的作用域scope

1.        Singleton

全局只有一个实例。节约内存。

2.        Prototype

每次调用getBean产生一个新的实例。

其他3种作用域的使用,需要在web.xml中配置

<listener><listener-class>org.springframework.web.context.request.RequestContextListener</listener-class></listener>

以便每次请求的开始和结束都可以使spring得到相应的事件。

3.        Request

每次请求都产生一个新的bean。

4.        Session

每个用户session产生一个新的bean,每个用户间的bean互不影响。

5.        globalSession

用于porlet环境,作用同session。

语法:

<bean id=”” class=”” scope=”singleton” />

四、       依赖注入DI

IoC和DI本质上都是剥离控制权,分离创建对象与使用对象的过程、思想或方法。DI可以说是IoC的一种实现方式,如果说DI与一般的IoC的区别,既然DI也是IoC,那么DI也涉及到控制反转的过程。DI要控制谁?同样是组件。要反转给谁?从创建对象的时机上来看,控制权看起来是给了组件。差别就在这里,一般IoC,是把控制权直接反转给spring容器,是站在容器的角度,站在spring的角度,而DI是从时机上直接反转给组件,是站在组件的角度来做分离,通过给与创建对象的控制权,使组件间形成了依赖关系。当然,由于最终组件的控制权依然归spring,所以,即使是DI没有直接将组件的控制权交给spring,但是spring可以间接的管理到这些或这个组件。所以,IoC和DI可以认为是从不同的层面,在不同的角度阐释剥离控制权,相互交融,没有本质区别。

依赖注入,一般是类属性注入到类,也就是对类的属性赋值或者赋引用,而这个属性可以基本类型也可以是引用类型。引用类型的注入在体现IoC上更明显。一般有3种方式实现属性的依赖注入。

(一)            构造器参数注入

1.        创建需要构造注入的类。

2.        配置xm文件。配置Bean的构造参数。

3.        例子

public class Car {

   private Stringname;

   private doubleprice;

   private Integercode;

   public Car(Integercode,Stringname,doubleprice){

      this.code=code;

      this.price=price;

      this.name=name;

   }

   public voidgetCar(){

      System.out.println(name+"--"+price+"--"+code);

   }

}

    <!-- 使用构造器参数注入属性 -->

    <beanid="carDI"class="com.edu.ioc.test2.Car">

       <!--

          index:参数索引的下标

          name:参数的名字

          type:参数的类型,使用type,相同类型参数会产生冲突

        -->

       <constructor-argindex="0"value="2"/>

       <constructor-argname="price">

          <value>22.22</value>

       </constructor-arg>

       <constructor-argtype="java.lang.String"value="哈哈"/>

    </bean>

如果构造参数的类型为引用类型,则xml中先装配这个类型的bean,再使用ref引用这个类型的bean。

如:

    <!-- 装配enginebean -->

    <beanid="engine"class="com.edu.ioc.test2.Engine">

       <!-- 使用构造器参数注入属性 -->

       <constructor-argname="name"value="h哈哈555"/>

       <constructor-argname="price"value="5"/>

</bean>

    <!-- 使用构造器参数注入属性 -->

    <beanid="carDI"class="com.edu.ioc.test2.Car">

       <!--

          index:参数索引的下标

          name:参数的名字

          type:参数的类型,使用type,相同类型参数会产生冲突

        -->

       ……

        <constructor-argname="engine"ref="engine"/>

   </bean>

(二)            Setter方法注入(setter方法要符合JavaBean的规范)

1.        创建要被注入的引用类型

2.        在注入目标创建setter方法

3.        配置xml文件。

4.        例子

public class Car2 {

   private Stringname;

   private doubleprice;

   private Integercode;

   private Engineengine;

   public voidsetName(String name){

      this.name =name;

   }

   public voidsetPrice(doubleprice){

      this.price =price;

   }

   public voidsetCode(Integer code){

      this.code =code;

   }

   public voidsetEngine(Engine engine){

      this.engine =engine;

   }

   public voidgetCar(){

      System.out.println(name+"--"+price+"--"+code+"--"+engine);

   }

}

    <!-- 使用setter方法 -->

   <beanid="carDISetter"class="com.edu.ioc.test2.Car2">

   <!-- property 设置setter方法属性的值或者引用 -->

       <propertyname="name"value="到底"></property>

       <!-- <property name="price"value="22.2"></property> -->

       <propertyname="price">

          <value>22.2</value>

       </property>

       <propertyname="code"value="5"></property>

       <!-- <property name="engine" ref="engine"></property>-->

       <!-- 或者 -->

       <propertyname="engine">

          <refbean="engine"></ref>

       </property>

   </bean>

</beans>

(三)            P命名空间注入

1.        创建一个schema约束的名称空间,赋值为P。

xmlns:p="http://www.springframework.org/schema/p"

2.        同setter方式注入,创建好被注入的类以及注入目标类。

3.        配置xml文件。

4.        例子

其他同setter方法,主要是xml文件的区别。

   <!-- 使用p命名空间的方式

       p取代<property>简化配置

    -->

   <bean id="carp" class="com.edu.ioc.test2.Car2"p:code="24"p:name="heh"p:price="255"p:engine-ref="engine"/>

(四)            SpEL表达式

Spring expression language,spring的el表达式,是spring3.0以上的新特性。

语法:#{…},引用另一个bean或它的属性,方法,运算。如:#{beanid},#{beanid.属性},#{beanid.方法(参数)}。如果使用spel表达式,可以引用类型,可以不需要使用ref。

例子:

   <!-- spel表达式

       注意:如果使用引用类型的属性,需要相关的引用类型通过getter方法获得需要使用的属性

    -->

   <bean id="carspel" class="com.edu.ioc.test2.Car2"p:name="#{engine.name}"p:code="#{12}"p:price="#{engine.price}"p:engine="#{engine}"/>

(五)            集合类型的注入

1.        创建含有集合属性的类,设置setter方法。

2.        配置xml。

3.        例子

创建类略。

   <!-- 集合的注入 -->

   <beanid="collections"class="com.edu.ioc.test2.CollectionDI">

       <propertyname="list">

          <list>

             <value>hah</value>

             <value>hah2</value>

             <value>hah3</value>

             <value>hah4</value>

          </list>

       </property>

       <propertyname="set">

          <set>

             <value>hah</value>

             <value>hah2</value>

             <value>hah3</value>

             <value>hah4</value>

          </set>

       </property>

       <propertyname="map">

          <map>

             <entrykey="1"value="kk"></entry>

             <entrykey="2"value="kk2"></entry>

             <entrykey="2"value="kk2"></entry>

          </map>

       </property>

       <propertyname="properties">

          <props>

             <propkey="hh">ljl</prop>

             <propkey="hh2">lj2l</prop>

             <propkey="hh3">lj3l</prop>

          </props>

       </property>

   </bean>

五、       Bean的生命周期

在spring的bean工厂,可以控制bean的声明周期。通过配置xml的方式实现。

1.        创建一个bean,创建其标识初始化和销毁的方法。

2.        配置xml。

3.        例子

public class BeanLifeCycle {

   public BeanLifeCycle(){

      System.out.println("构造了一个bean");

   }

   public voidinit(){

      System.out.println("初始化了");

   }

   public voiddestroy(){

      System.out.println("销毁了");

   }

}

   <!-- 配置bean的生命周期 -->

   <bean id="beanLife" class="com.edu.ioc.test2.BeanLifeCycle"init-method="init"destroy-method="destroy"></bean>

   @Test

   public voidtestlife(){

      ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");

      BeanLifeCycle blc=(BeanLifeCycle)ac.getBean("beanLife");

      //由于java虚拟机已经关闭,所以没有来得及执行销毁的方法。

      //可以手动关闭spring容器,执行销毁方法。

      ((ClassPathXmlApplicationContext)ac).close();

      System.out.println(blc);

   }

4.        关于销毁方法的执行,需要手动关闭容器,将ApplicationContext强转为具有close方法的实现类,然后再执行close方法。

六、       基于注解的方式装配Bean。

(一)            导入需要的jar包

Core,bean,context,expression,aop(spring4以上需要aop支持注解)。

(二)            导入日志包和添加log4j的日志配置文件。

Logging,log4j

(三)            配置核心配置文件

1.        创建applicationContext.xml

引用spring官方提供的关于注解的schema。这个schema在xml装配bean的基础上,另外加上xmlns:context=“http://www.springframework.org/schema/context

http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd。详见下:

<?xml version="1.0"encoding="UTF-8"?>

<beansxmlns="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/contexthttp://www.springframework.org/schema/context/spring-context.xsd

">

 

</beans>

(四)            例子

1.        创建用于测试注解的类,使用@Component添加注解类。

2.        在xml开启注解的功能

3.        测试

import org.springframework.stereotype.Component;

//@Component的作用,将类注解为bean。相当于<bean id="testAnnotation"class="com.edu.ioc.test2.TestAnnotation" />

//如果不为注解类赋值,那么注解的beanid是类名首字母小写。

//@Component(value="自定义的id名字")

@Component

public class TestAnnotation {

   public voidtestAnnotation(){

      System.out.println("使用注解装配bean得到的对象");

   }

}

----------------------------------------------------------------------------------------------

   <!-- 开启注解的功能,使注解生效 -->

   <context:annotation-config></context:annotation-config>

   <!-- 配置注解扫描,自动扫描将@Component标注的类注解为beanbase-package表示扫描域

       由于配置注解扫描的时候,会开启注解,所以可以省略context:annotation-config

   -->

   <context:component-scanbase-package="com.edu.ioc.test2"/>

----------------------------------------------------------------------------------------------

   @Test

   public voidtestAnnotation(){

      ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");

      TestAnnotation ta=(TestAnnotation)ac.getBean("testAnnotation");

      ta.testAnnotation();

   }

(五)            衍生注解

@Service用于标注业务层组件。如service层。

@Repository用于标注数据访问组件。如dao层。

@Controller用于标注控制层组件。如springmvc的controller层和struts2的action层。

@Component泛指其他不好归类的组件。

例子:

@Service

Public class UserServiceImpl implements UserService{…..}

@Repository

Public class UserDaoImpl implements UserDao{…..}

(六)            基于注解的依赖注入

1.        简单数据类型的依赖注入

在需要注入的属性上标注@Value(value=””)。

   /*

    * @Value(value=""),将基本类型数据的属性注入类,()里的value可以省略。

    */

   @Value(value="zhangsan")

   private String name;

2.        复杂数据类型的依赖注入

主要是引用数据类型。

1)        使用@Value(value=”spel”)

   @Value(value="#{annotationDI}")

   private AnnotationDI annotationDi;

同时,在被注入的引用类型上要标注注解,将其装配到bean工厂。

@Repository

public class AnnotationDI {

   ……

}

2)  使用@Autowired

如果标注的是一个类,则将这个类注入属性。如果是一个接口,则将这个接口的实现类注入属性。当是一个接口的时候,如果这个接口有多个实现类,则报错。

注意:当注解注入接口的时候,需要对接口的实现类进行注解,否则找不到实现类的bean而报错。

   注解注入一个类

@Autowired

   private AnnotationDI annotationDi;

   注解注入一个接口,自动注入这个接口的实现类

   @Autowired

   private AnnotationInterface annotationDi;

@Autowired配合@Qualifier

@Qualifier可以指定具体的实现类的bean。同样的,在被指定的实现类中需要将给这个类装配bean。

   @Autowired

   @Qualifier(value="annotationDI2")

   private AnnotationInterfaceannotationDi;

3)       @Resource(name=”…”)

这是基于jdk的注解。Name值为bean的id。

   @Resource(name="annotationDI")

   private AnnotationInterfaceannotationDi;

(七)            基于注解的Bean的生命周期

@PostConstruct将方法注解为初始化方法,相当于<bean ….    Init-method=”…”/>

@PreDestroy将方法注解为销毁方法,相当于<bean …. Destroy-method=”….” />

同xml装配bean一样,如果想执行销毁方法,需要对象装配的bean为singleton,且调用容器的close方法。

例子:

@Controller

public class BeanLifeCycle {

   public BeanLifeCycle(){

      System.out.println("构造了一个bean");

   }

   @PostConstruct

   public voidinit(){

      System.out.println("初始化了");

   }

   @PreDestroy

   public voiddestroy(){

      System.out.println("销毁了");

   }

}

测试略。

(八)            基于注解的bean的作用域scope

@scope(value=”…”)

Singleton,prototype,request,session, globalsession等

例子:

@Scope(value="prototype")

public classBeanScope {

   ……

}

七、       混合使用xml和注解装配bean的方式

实际开发中,请按需求使用

例子:

public class XmlBeanDITO {

   public voidintro(){

      System.out.println("我是在xml中装配了bean,自身没有标注注解的类,同时我将在XmlBeanDIGet中通过使用注解的方式注入到从属类XmlBeanDIGet中。");

   }

}

-----------------------------------------------------------------------------------------

public class XmlBeanDIGet {

   @Autowired

   private XmlBeanDITObeanDiTo;

   public voidgetByAnnotation(){

      beanDiTo.intro();

   }

}

   <!-- 开启注解和注解扫描 -->

   <context:annotation-config></context:annotation-config>

   <context:component-scanbase-package="com.edu.ioc.test3"/>

   <!-- 装备bean -->

   <beanid="xmlBeanDIGet"class="com.edu.ioc.test3.XmlBeanDIGet"/>

   <bean id="xmlBeanDITO"class="com.edu.ioc.test3.XmlBeanDITO"/>

八、    Web集成

直接将web层集成到spring管理。例如:将servlet创建service对象,调用其方法的过程由spring操办。

如果,单纯的由spring管理web层的业务。那么,每次访问web,都会重新对spring中的bean初始化。相当于重新创建了容器,这样消耗了资源,降低了性能。

为了改善,需要保证spring容器在web服务过程中的唯一。在web中,servletContext是唯一的,可以考虑将spring容器绑定到servletContext上。也就是说需要xml文件在servletContext中只加载一次。servletContext本身自带了servletContextListener监听器,可以帮助实现对上下文中属性的监听。由于,spring提供了专门用于监听上下文加载的监听器,我们可以直接使用。需要导入spring的web jar包。

重点:在web.xml配置监听器以及web层集成到spring的方式。

  <listener>

  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

  </listener>

  <context-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>classpath:applicationContext3.xml</param-value>

  </context-param>

   public voiddoGet(HttpServletRequest request, HttpServletResponseresponse)throwsServletException, IOException {

//    ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext3.xml");

//    HelloServiceImpl hs=(HelloServiceImpl)ac.getBean("helloServiceImpl");

//    hs.hello();

      //全局单次加载核心配置文件之web集成到spring

      //方式1

//    ApplicationContextac2=(ApplicationContext)this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

//    HelloServiceImplhs2=(HelloServiceImpl)ac2.getBean("helloServiceImpl");

//    hs2.hello();

      //方式2

      ApplicationContext ac3=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());

      HelloServiceImpl hs3=(HelloServiceImpl)ac3.getBean("helloServiceImpl");

      hs3.hello();

   }

九、    Junit测试集成

将junit集成到spring,简化测试代码,提高效率。请导入spring的test包和junit(jdk自带这个包的)的jar包。

在需要测试的类上

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:applicationContext3.xml")

同时在需要测试的类里面,将使用的对象注解注入或者xml注入到这个类。

例子:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:applicationContext3.xml")

public class TestXmlAndAnnotation {

   @Autowired

   private XmlBeanDIGetxmlBeanDIGet;

   @Test

   public voidtest1(){

      xmlBeanDIGet.getByAnnotation();

   }

}