spring学习(转载)

来源:互联网 发布:淘宝收件人名字大全 编辑:程序博客网 时间:2024/06/15 06:20
本文转自:<a target=_blank href="http://blog.csdn.net/lishuangzhe7047/article/details/20740209">http://blog.csdn.net/lishuangzhe7047/article/details/20740209</a>

 

1,什么是spring框架

springJ2EE应用程序框架,是轻量级的IoCAOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。

2,架构概述

  1IoC(Inversion of Control)控制反转,对象创建责任的反转,在springBeanFacotoryIoC容器的核心接口,负责实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。XmlBeanFacotory实现BeanFactory接口,通过获取xml配置文件数据,组成应用对象及对象间的依赖关系。

spring中有三种注入方式,一种是set注入,一种是接口注入,另一种是构造方法注入。

    2AOP面向切面编程

   aop就是纵向的编程,如下图所示,业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。

spring中面向切面变成的实现有两种方式,一种是动态代理,一种是CGLIB,动态代理必须要提供接口,而CGLIB实现是有继承。

3,为什么使用spring框架

  在不使用spring框架之前,我们的service层中要使用dao层的对象,不得不在service层中new一个对象。如下:

 

//dao层对象public class UserDao{   publicvoid insert(User user){}} //service层对象public classUserService{   publicvoid insert(User user){       UserDaouserdao = new UserDao();       userdao.insert(user);   }}


存在的问题:层与层之间的依赖。

使用框架后:

//dao层对象public class UserDao{    publicvoid insert(User user){}} //service层对象public classUserService{   privateUserDao userdao;    publicUserDao getUserdao() {      returnuserdao;   }   publicvoid setUserdao(UserDao userdao) {      this.userdao= userdao;   }    publicvoid insert(User user){      userdao.insert(user);   } }


service层要用dao层对象需要配置到xml配置文件中,至于对象是怎么创建的,关系是怎么组合的都交给了spring框架去实现。

4,框架优点

轻量级的容器框架没有侵入性

使用IoC容器更加容易组合对象直接间关系,面向接口编程,降低耦合

Aop可以更加容易的进行功能扩展,遵循ocp开发原则

创建对象默认是单例的,不需要再使用单例模式进行处理

5,缺点:业务功能依赖spring特有的功能,依赖与spring环境。

 

(二) 依赖注入

spring框架为我们提供了三种注入方式,分别是set注入,构造方法注入,接口注入。接口注入不作要求,下面介绍前两种方式。


1set注入

  采用属性的set方法进行初始化,就成为set注入。

    1)给普通字符类型赋值。

public class User{   privateString username;    publicString getUsername() {       returnusername;   }   publicvoid setUsername(String username) {      this.username= username;   }}


  我们只需要提供属性的set方法,然后去属性文件中去配置好让框架能够找到applicationContext.xml文件beans标签。标签beans中添加bean标签,指定idclass值,id值不做要求,class值为对象所在的完整路径。bean标签再添加property 标签,要求,name值与User类中对应的属性名称一致。value值就是我们要给User类中的username属性赋的值。

<bean id="userAction"class="com.lsz.spring.action.User" ><span style="white-space: pre;"></span><property name="username" value="admin"></property></bean>


2)给对象赋值

同样提供对象的set方法

public class User{     private UserService userservice;     public UserServicegetUserservice() {          returnuser;     }     public void setUserservice(UserService userservice){         this.userservice= userservice;     }}


配置文件中要增加UserServicebean标签声明及User对象对UserService引用。

<!--对象的声明--><bean id="userService" class="com.lsz.spring.service.UserService"></bean> <bean id="userAction"class="com.lsz.spring.action.User" >   <property name="userservice" ref="userService"></property></bean>


 

  这样配置,框架就会将UserService对象注入到User类中。

  3)给list集合赋值

同样提供set方法

public class User{    privateList<String> username;    publicList<String> getUsername() {        returnusername;    }    publicvoid setUsername(List<String> username) {        this.username= username;    }}


 

<bean id="userAction"class="com.lsz.spring.action.User" >     <propertyname="username">           <list>               <value>zhang,san</value>               <value>lisi</value>               <value>wangwu</value>                                               </list>    </property></bean>


4)给属性文件中的字段赋值

public class User{    privateProperties props ;    publicProperties getProps() {        returnprops;    }    publicvoid setProps(Properties props) {        this.props= props;    }}


 

<bean>    <propertyname="props">        <props>           <propkey="url">jdbc:oracle:thin:@localhost:orl</prop>           <propkey="driverName">oracle.jdbc.driver.OracleDriver</prop>           <propkey="username">scott</prop>           <propkey="password">tiger</prop>        </props>    </property></bean>


 

<prop>标签中的key值是.properties属性文件中的名称


注意:

  无论给什么赋值,配置文件中<property>标签的name属性值一定是和对象中名称一致。

2构造方法注入

   1)构造方法一个参数

public class User{    privateString usercode;    publicUser(String usercode) {        this.usercode=usercode;    }}


 

<bean id="userAction"class="com.lsz.spring.action.User">                            <constructor-argvalue="admin"></constructor-arg>                        </bean>


2)构造函数有两个参数时

  当参数为非字符串类型时,在配置文件中需要制定类型,如果不指定类型一律按照字符串类型赋值。

当参数类型不一致时,框架是按照字符串的类型进行查找的,因此需要在配置文件中制定是参数的位置

<constructor-argvalue="admin"index="0"></constructor-arg>                <constructor-argvalue="23" type="int"index="1"></constructor-arg> 


这样制定,就是构造函数中,第一个参数为string类型,第二个参数为int类型

 

 

(三)Junit单元测试

单元测试不是头一次听说了,但只是听说从来没有用过。一个模块怎么测试呢,是不是得专门为一单元写一个测试程序,然后将测试单元代码拿过来测试? 我是这么想的。学到spring框架这才知道单元测试原来是这么回事儿。


下面以上一篇文章中set注入的第一个实例为测试对象。进行单元测试。


1,拷贝jar包

junit-3.8.2.jar(4.x主要增加注解应用)


2,写业务类

 

public class User{    privateString username;     publicString getUsername() {       returnusername;    }    publicvoid setUsername(String username) {       this.username= username;    }     //添加方法    publicString login() throws Exception{       if("admin".equals(username){          return"success";       }else{          return"error";       }    }}


 

3,定义测试类

  测试类最好单独建立项目,或者单独定义文件夹存储,需要继承junit.framework.TestCase

4,增加测试方法

测试方法必须是public,不应该有返回值,方法名必须以test开头,无参数

测试方法是有执行先后顺序,按照方法的定义先后顺序

多个测试方法对同一个业务方法进行测试,一般每个逻辑分支结构都有测试到。

public class TestUserextends TestCase{     publicvoid testUser_Success() throws Exception{        //准备数据       Useraction = new User();       action.setUsername("admin");       //调用被测试方法       Stringresult = action.login();        //判断测试是否通过       assertEquals("success",result);     }}


运行程序,如果测试成功会出现如下图所示的结果

如果运行失败,有方法没有通过测试,那么就会显示出在哪个方法出错了。上图中绿色的条会变成红色的。

5,测试类的生命周期方法

 //用来进行初始化操作@Overrideprotectedvoid setUp() throws Exception {   System.out.println("setUp...");} //用来做销毁操作@Overrideprotectedvoid tearDown() throws Exception {   System.out.println("tearDown...");}


setUp方法会在每一个测试方法前执行一次。tearDown方法会在每一个测试方法后执行一次。

 

(四)自动装配

set注入和构造注入有时在做配置时比较麻烦。所以框架为了提高开发效率,提供自动装配功能,简化配置。Spring框架式默认不支持自动装配的,要想使用自动装配需要修改spring配置文件中<bean>标签的autowire属性

自动装配属性有6个值可选,分别代表不同的含义。

1,byName

从Spring环境中获取目标对象时,目标对象中的属性会根据名称在整个Spring环境中查找<bean>标签的id属性值。如果有相同的,那么获取这个对象,实现关联。

整个Spring环境:表示所有的spring配置文件中查找,那么id不能有重复的。

2,byType

从Spring环境中获取目标对象时,目标对象中的属性会根据类型在整个spring环境中查找<bean>标签的class属性值。如果有相同的,那么获取这个对象,实现关联。

缺点:如果存在多个相同类型的bean对象,会出错。

       如果属性为单一类型的数据,那么查找到多个关联对象会发生错误。

       如果属性为数组或集合(泛型)类型,那么查找到多个关联对象不会发生异常。

3,constructor

使用构造方法完成对象注入,其实也是根据构造方法的参数类型进行对象查找,相当于采用byType的方式。

4,autodetect

自动选择:如果对象没有无参数的构造方法,那么自动选择constructor的自动装配方式进行构造注入。如果对象含有无参数的构造方法,那么自动选择byType的自动装配方式进行setter注入。                     

5,no

不支持自动装配功能

6,default

表示默认采用上一级标签的自动装配的取值。如果存在多个配置文件的话,那么每一个配置文件的自动装配方式都是独立的。                  

如果配置文件存在多个的情况下,加载配置文件的方式:

1)可以指定总的配置文件去包含子的配置文件,然后只加载总的配置文件即可在总的配置文件applicationContext.xml中使用import标签进行子文件包<importresource="applicationContext-test.xml"/>

代码中加载配置文件:

<span style="font-size: 18px;">ApplicationContextac= newClassPathXmlApplicationContext("applicationContext.xml");</span>


2)使用星号来匹配多个文件进行加载,文件名称要符合规律。 (推荐使用)

<span style="font-size: 18px;">   //配置文件的名称applicationContext.xmlapplicationContext-action.xmlapplicationContext-service.xmlapplicationContext-dao.xml ApplicationContextac =newClassPathXmlApplicationContext("applicationContext*.xml"); </span>


3)可以使用数组作为参数,一次性加载多个配置文件

 String[]files={"applicationContext.xml","applicationContext-test.xml"};               ApplicationContextac = newClassPathXmlApplicationContext(files);      


注意:自动装配功能和手动装配要是同时使用,那么自动装配就不起作用。

 

(五)注解

  注解Annotation,是一种类似注释的机制,在代码中添加注解可以在之后某时间使用这些信息。跟注释不同的是,注释是给我们看的,java虚拟机不会编译,注解也是不编译的,但是我们可以通过反射机制去读取注解中的信息。注解使用关键字@interface,继承java.lang.annotition.Annotition

 

spring框架为我们提供了注解功能。

  使用注解编程,主要是为了替代xml文件,使开发更加快速。但是,xml文件的使用就是解决修改程序修改源代码,现在又不去使用xml文件,那么不就违背了开闭原则了么,得确是。不过么,注解也有注解的好,使用注解就不用配置那么多的xml文件啦,最重要的是开发效率高。。

  在没有使用注解时,spring框架的配置文件applicationContext.xml文件中需要配置很多的<bean>标签,用来声明类对象。使用注解,则不必在配置文件中添加标签拉,对应的是在对应类的“注释”位置添加说明。具体介绍如下:

   spring框架使用的是分层的注解。

    持久层:@Repository

    服务层:@Service

    控制层:@Controller

1,使用注解,需要在配置文件中增加命名空间和约束文件

<beans ...xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="...http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd">


 

2,告诉框架那些类是使用注解的。

<context:component-scan base-package="com.lsz.spring" />

3,持久层注解

Package com.lsz.spring; @Repositorypublic class UserDao{//。。。。}


@Repository等同于配置文件中的

<bean id="userDao" class="com.lsz.spring.UserDao" />


4,服务层注解

@Service(value="testService")public classTestService { @Resource//相当于自动装配private UserDao userDao ;       public UserDao getUserDao() {              returnuserDao;      }      public void setUserDao(UserDao userDao) {             this.userDao= userDao;      } }


 

@Resource对象间关系的组合,默认采用的是byName方式进行装配,如果根据名称查找不到关联的对象,那么会再采用byType继续查找。

@Service注解等同与

<bean id="testService" class="com.lsz.spring.UserService" />


5,控制层注解

@Controller(value="ua")@Scope(value="prototype")public class UserAction {      @Resource     private UserService userService ;      public UserService getUserService() {          returnuserService;     }}


@Controller注解等同于

<bean id="ua" class="com.lsz.spring.UserAction " />


这三个层中的注解关键字都可以使用@Component来代替。

使用注解声明对象,默认情况下生成的id名称为类名称的首字母小写。

6,从Spring环境中获取Action对象。

ServletContext application =request.getSession().getServletContext();ApplicationContextac = WebApplicationContextUtils.getWebApplicationContext(application); UserAction useraction = (UserAction)ac.getBean("ua");//获取控制层对象response.setContentType("text/html;charset=GBK");//设置编码PrintWriter out =response.getWriter();//分别将三个层的对象打印出来。out.println("Action:"+userAction);out.println("Service:"+userAction.getUserService());out.println("Dao:"+userAction.getUserService().getUserDao());


 

 

(六)AOP

AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象。

AOP的引入

OOP面向对象的使用中,无可避免的会出现代码重复,而且使用面向对象的编程方式,这种重复无法避免,比如用户权限判断中,根据相应的权限执行相应的方法;在servlet中设置编码格式时,同样相同的代码出现很多次,而且还根业务无关,很容易忘记写,结果运行的时候就出现乱码拉。这种重复代码不仅使编码麻烦,而且还不容易维护。而AOP则将这些代码整理起来,将解决某个切面问题的代码单独的放在某个模块中,然后再织入到程序中。

AOP中的术语

Aspect:横切面的功能,抽象出类,或接口, AOP编程重要的就是识别出横切面功能。

      方面,类似于字符编码功能

Advice: 横切面功能的具体实现,需要根据实际的情况分析,如果在目标对象操作之前是 before在操作之后,就是 after advice。

      增强,类似于字符编码过滤器

Pointcut:切入点,描述横切面功能应用的限制,不是所有的流程都需要,那些可以使用的地方就是切入点

      类似于过滤器的匹配规则 /*

Joinpoint: 连接点,或指组件加入流程的时机,比如设置属性,调用方法,等,Spring只支持方法调用的连接点,而其他的一些框架支持属性的连接点如:AspectJ

      类似于过滤器的过滤规则 REQUESTFORWARD

Weave:缝合,将组件应用到业务流程中的这个过程,叫缝合或织入。

      类似于将过滤器配置到web.xml文件的过程

Proxy,代理,在实现上,SpringAOP其实就是使用JDK的动态代理(使用接口的方式完成代理操作),也可以使用CGLIB(使用继承的方式完成代理操作)。

Target目标,业务操作的实际对象

实例:设置字符编码格式看作是一个Aspect方面,而拦截器就是一个Advice增强。

<span style="font-size: 18px;"><!-- 字符编码过滤器--><filter><filter-name>characterFilter</filter-name><filter-class>com.bjpowernode.egov.filter.CharacterEncodingFilter</filter-class></filter><filter-mapping><filter-name>characterFilter</filter-name><url-pattern>/servlet/*</url-pattern></filter-mapping> </span>


过滤器

<span style="font-size: 18px;">public class CharacterEncodingFilter implements Filter {    @Override   public void destroy() {}    @Override   public void doFilter(ServletRequest request, ServletResponse response,      FilterChainchain) throws IOException, ServletException {           request.setCharacterEncoding("GB18030");           chain.doFilter(request,response);   }    @Override   publicvoid init(FilterConfig filterConfig) throws ServletException {}}</span>


 

这样就不用在每个servlet中设置编码拉。。

spring框架中AOP的使用

1,拷贝jar

2spring配置文件中增加命名空间和约束文件

启用aop功能:就把标签添加进来就可以拉。

 

3,写被代理的类和扩展类

 

4,由配置文件声明

<span style="font-size: 18px;"><!--声明目标类--><bean id="targetclass" class="com.spring.aop.TargetClass"></bean><!--声明扩展类--><bean id="extendsclass" class="com.spring.aop.extendsClass"></bean><!--织入扩展类,并声明在哪个方法上执行扩展类--><aop:config><aop:aspect id="extendAspect" ref=""><aop:pointcut expression="execution(public ** (..))" id="extendsPoincat"><!--在目标方法执行前执行的方法--><aop:before method="beforemethod" pointcut-ref="extendsPoincat" /><!--在目标方法执行后执行的方法--><aop:after method="aftermethod" pointcut-ref="extendsPoincat" /></aop:aspect></aop:config></span>


 

5,测试

成功的话,执行目标类中的目标方法targetmethod()时,会先执行扩展类中的beforemethod()方法,再执行目标方法,最后再执行aftermethod()方法。
也就是我们只需要手动调用targetmethod方法,扩展类中的两个方法框架会在执行的时候通过读取配置文件,获取相应信息,自动给我们添加上扩展的方法。。
测试肯定成功,不相信的话,可以自己试试。

Spring框架中使用AOP的优点

   AopspringIOC容器整合,增强,切入点都是javabean,可以在同一文件中配置

spring的其他部分一样,可以在不同应用服务器之间任意移植

   spring实现Aop的拦截接口,使得用户不必绑定在特定的拦截器接口上

aop面向切面的编程思想,打破面向对象的思维方式,我们要学习的不仅是aop的使用,更要学习面向切面的这种思想。

 

 

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

其他类似参考:

http://developer.51cto.com/art/201006/205212.htm

 

 

0 0