那些年我们一起一步一步追过的SSM框架


                      写在前面的话:


   初识框架感觉比较混乱,感觉是东搞一下,西搞一下,各种配置,但当我们把这些配置集合在一起,发现这个东西很神奇,就像有了一本武林秘籍一样,对于我们开发无往不利,业务逻辑清清楚楚,丝毫不混乱,你的业务该怎么实现,他的该怎么实现,都有很清楚的实现过程,不会让我们感到棘手,不知如何下手,每一层所履行的责任,都明明白白,反过来一想,如果我们没有框架,程序员的工作就很痛苦,所有的业务融合在一起,想想都很头痛,就想修房子一样,我们总不能把家具先往那一放,就开始修房子吧,总得先搭个框架。这才是我们所需要的!废话不多话,开始介绍我们的框架。


NO-1:何为框架

框架(Framework)是一个框子——指其约束性,也是一个架子——指其支撑性。

       那么到底什么是Java框架呢?

Java框架就是一些类和接口的集合,通过这些类和接口协调来完成一系列的程序实现。框架又叫做开发中的半成品,

是一组组件,但是这个东西复用性特别的强,可以让广大程序开发人员完成自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。


它不能提供整个WEB应用程序的所有东西,但是有了框架,我们就可以集中精力进行业务逻辑的开发而不用去关心它的技术实现以及一些辅助的业务逻辑。说白了Java框架就是封装好方便程序员操作的类,使项目的开发更简单,维护起来也更容易。

框架在程序中的使用可以使程序的更容易扩展,更容易维护,稳定性更强。 

那么为什么要用框架呢?

        因为软件系统发展到今天已经很复杂了,特别是服务器端软件,设计到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。而且框架一般是成熟,稳健的,他可以处理系统很多细节问题,比如,事物处理,安全性,数据流控制等问题。还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处。


NO-2--Mybatis框架


   mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement(Statement 是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。Statement对象,用于执行不带参数的简单SQL语句)等繁杂的过程。

  

   由上述的介绍中,我们发现一个很关键的一句话,内部封装了JDBC(数据库连接),那么Mybatis最核心的就是数据库的操作,我们Mybatis最核心的就是POJO和SQL之间的映射关系


  那么接下来我们就看一下Mybatis的配置步骤:


  《1》--创建一个javaweb项目

  

 《2》--导入mybatis所需jar包



 

 《3》添加mybaits配置文件

  

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

<!DOCTYPEconfiguration

  PUBLIC "-//mybatis.org//DTDConfig 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-config.dtd"

 >

<configuration>

 <environmentsdefault="development">

   <environmentid="development">

     <transactionManagertype="JDBC"/>

     <!-- 配置JDBC的属性 -->

     <dataSourcetype="POOLED">

        <!--表示的是数据库的连接驱动 -->

        <propertyname="driver"value="oracle.jdbc.driver.OracleDriver"/>

        <!-- 表示的是连接字符串 -->

        <propertyname="url"value="jdbc:oracle:thin:@localhost:1521:orcl"/>

        <propertyname="username"value="hotelsup"/>

        <propertyname="password"value="123"/>

     </dataSource>

   </environment>

 </environments>

 <mappers>

 </mappers>

</ configuration >

                  

《4》创建实体对象


public class UserInfo implements Serializable {

public UserInfo(Integer userid, String username, String userpwd,
String card, String job, String del) {
super();
this.userid = userid;
this.username = username;
this.userpwd = userpwd;
this.card = card;
this.job = job;
this.del = del;
}

public UserInfo() {
super();
}


private Integer userid;//用户id
private String username;//用户账号
private String userpwd;//用户密码
private String card;//身份证号
private String job;//职业
private String del;//是否删除
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
this.userpwd = userpwd;
}
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public String getDel() {
return del;
}
public void setDel(String del) {
this.del = del;
}
    


}


《5》创建一个对于数据库增删改查的借口


 

《6》定义操作表的sql映射文件UserInfoMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="UserInfoMapper">

<!-- 在各种标签中的id属性必须和接口中的方法名相同 , id属性值必须是唯一的,不能够重复使用。parameterType属性指明查询时使用的参数类型,resultType属性指明查询返回的结果集类型-->    
<!--

      #相当于是在jdbc里的?,传进去的值可以设置其数据类型。会根据传入的数据类型自动加字符串的单引号或者不加单引号。预处理参数。可以防止SQL注入。

     $相当于是我们的JDBC里的字符串拼接。这里就相当于传入的就是一个字符串(不管传入什么样的数据类型,都是字符串)

-->

<!--定义公共的sql语句-->


    <sql id="sqlItem">
      
      insert into userifo where del="N";
    
    </sql>
    <insert id="insertItem" keyColumn="userid" keyProperty="userid" useGeneratedKeys="true" parameterType="com.jinglin.hotelsup.model.UserInfo">
       insert into userinfo(userid,username,userpwd,card,job)
       values(userseq.nextval,#{username},#{userpwd},#{card},#{job})
    </insert>
    <select id="selectItem" resultType="com.jinglin.hotelsup.model.UserInfo"
    parameterType="java.lang.Integer">
      select * from userinfo where userid=#{id}
    </select>
    <delete id="delItem" parameterType="java.lang.Integer">
    
     delete  from userinfo where userid=#{id}
    </delete>
    <update id="upItem" parameterType="com.jinglin.hotelsup.model.UserInfo">
    update userinfo set username=#{username},userpwd=#{userpwd},card=#{card},job=#{job}
    where userid=#{userid}
    </update> 
    <select id="selectlist" resultType="com.jinglin.hotelsup.model.UserInfo">
      select * from userinfo
    
    </select>
    <insert id="insertItems" parameterType="com.jinglin.hotelsup.model.UserInfo">
    
    </insert>
    
    <select id="selectlike" resultType="com.jinglin.hotelsup.model.UserInfo">
    
    select * from userinfo where username like '%${value}%'
    
    </select>
    
</mapper>

《6》 将UserInMapper.xml配置到mybatis-config。xml文件中

<mappers>

    <mapperresource="com/jinglin/hotelsup/model/UserInfoMapper.xml"/>

  </ mappers >

《7》测试类-实现对数据的操作

package com.jinglin.hotelsup.test;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jinglin.hotelsup.model.UserInfo;
import com.jinglin.hotelsup.service.UserInfoService;


public class TestUserInfo {
    static Logger logger=Logger.getLogger(UserInfo.class);//存入日志信息
    
    static ClassPathXmlApplicationContext ac=null;
static{
ac =new ClassPathXmlApplicationContext("applicationContext.xml");
}

@Test

public void testit(){

    UserInfoService userInfoService =(UserInfoService)ac.getBean("userInfoService");
    UserInfo userinfo = new UserInfo();
userinfo.setCard("222");
userinfo.setUsername("admin124");
userinfo.setUserpwd("123");
    int result= userInfoService.adduser(userinfo);
    System.out.println("受影响的行数:"+result);
}


//添加某个字段的值
/*SqlSession sqlSession=sessionfactory.openSession();
UserInfoMapper userInfoMapper = sqlSession.getMapper(UserInfoMapper.class);*/
/* UserInfo userinfo = new UserInfo();
userinfo.setUsername("张思");
int result=userInfoMapper.insertItem(userinfo);
sqlSession.commit();
sqlSession.close();
System.out.println("受影响的行数:"+result);
System.out.println("当前插入的id:"+userinfo.getUserid());*/
//修改某个字段的值
/* UserInfo userinfo=new UserInfo();
userinfo.setUsername("张思邈");
userinfo.setUserid(21);
int result=userInfoMapper.updateItem(userinfo);
sqlSession.commit();
sqlSession.close();
System.out.println("受影响的行数:"+result);*/
//逻辑删除
/* int result=userInfoMapper.deleteItem(21);
sqlSession.commit();
sqlSession.close();*/
/*UserInfo userinfo = userInfoMapper.selectItem(21);
sqlSession.close();
System.out.println("查询到的名字:"+userinfo.getUsername());
*/
//修改
/* UserInfo userinfo = new UserInfo();
userinfo.setUserid(20);
userinfo.setCard("3111");
userinfo.setUsername("凤雏");
userinfo.setJob("程序员军师");
userinfo.setUserpwd("13222223");
int result=userInfoMapper.updateItem(userinfo);
    sqlSession.commit();
sqlSession.close();*/
//删除
/*int result=userInfoMapper.deleteItem(20);
   sqlSession.commit();
sqlSession.close();*/
//查询单条
/*UserInfo result=userInfoMapper.selectItem(2);
sqlSession.close();*/
//多条查询
/*       UserInfo userinfo=new UserInfo();
       userinfo.setUsername("张三丰");
       List<UserInfo> listuserinfo=userInfoMapper.selectItems(userinfo);
       for (UserInfo list : listuserinfo) {
System.out.println(list.getUsername());
}
*/
//添加
/*UserInfo   userinfo=new UserInfo();
userinfo.setCard("222221");
userinfo.setJob("工程师");
userinfo.setUsername("沈力");
userinfo.setUserpwd("321312");
int result=userInfoMapper.insertItem(userinfo);
sqlSession.commit();
sqlSession.close();
System.out.println("受影响行数"+result);
System.out.println("刚加入主键"+userinfo.getUserid());
*/

}
《8》--以上就是mybatis的开发配置步骤,最核心的还是我们的sql配置,对象的映射


NO-3--介绍我们第二款框架Spring


  提到Spring 我们首先想到Spring的七个模块



组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI
在Spring众多模块中,我们最常用,也是核心模块的当属AOP和IOC,需要我们熟练的掌握这两项核心模块

Spring是一个轻量级的IOCAOP容器框架:


                 a,轻量级:程序实现不是很复杂,代码不是很多,占用资源不是很多,没有侵入性;


                 bIOCInversion of Control 控制反转):对象创建责任的反转(重点,核心);


                 c, Aop(Aspect Oriented Programming):一种面向横切面编程的思想方式,可以进行功能性扩展


                 d,容器:可以容纳对象,并且可以控制对象的生命周期;

 

 

         二,看一下使用步骤吧!(框架用多了,感觉步骤都大同小异)

              1,还是拷贝jar包:


             2,拷贝框架的核心配置文件,存放在src目录下:



            3,编写框架的核心配置文件,将声明对象都交给Spring框架来创建,以及初始化,例如service层的类,action层类,dao层类等等,都可以交给Spring进行管理,看一个例子:


[html]  view plain  copy
 print ?
  1. <span style="font-size:18px;">      <!-- 声明Action对象 -->  
  2.   
  3. <bean id="loginAction" class="com.ljh.struts2.action.LoginAction" scope="prototype"></bean> </span>  
 


  分析:a,框架创建对象的方式:

                   框架默认创建对象是单例的:scope="singleton"

                   当然action我们想要多例创建,需要设置:scope="prototype"


              b,工厂BeanFactory,,如果使用BeanFactory来加载Spring配置文件,那么是在调用getBean时,框架调用对象的默认构造方法来创建对象。BeanFactory功能是对bean对象的生命周期进行管理的。(创建,初始化,销毁)。


             c,ApplicationContext(推荐,也是框架默认的)

               来用才对象来加载Spring配置文件,会在加载时解析配置文件,创建对象,而不是在getBean时创建。其实,ApplicationContext接口继承了BeanFactory,所以具备BeanFactory所有功能,同时增加扩展的功能,例如加载资源配置文件,国际化支持等!

 

         4,如何测试,这里我们可以使用Junit(java的单元测试进行测试)(我们现在是单独使用Spring为了是学习,后边会集成多个框架的)

 

  a,先看一下Junit单元测试的使用方法:Junit4详解

 

   b,利用beanFactory加载配置文件:

[java]  view plain  copy
 print ?
  1. <span style="font-size:18px;">      //加载配置文件,创建Spring的应用环境  
  2.         String path = "applicationContext.xml";       
  3.         Resource resource = new ClassPathResource(path);    //推荐  
  4.         //Resource resource = new FileSystemResource("src/applicationContext.xml");  
  5.         //Resource resource = new ServletContextResource(servletContext, path); //如果文件存放到WEB-INF目录下  
  6.           
  7.         BeanFactory factory = new XmlBeanFactory(resource);  
  8.   
  9.         //从Spring环境中获取对象  
  10.         Object obj = factory.getBean("loginAction");  
  11.           
  12.   
  13. LoginAction action = (LoginAction)obj ; </span>  

    c,  利用ApplicationContext加载配置文件:

[java]  view plain  copy
 print ?
  1. <span style="font-size:18px;">      ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");  
  2.               
  3.         Object obj = ac.getBean("loginAction");  
  4. </span>  

              这就是Spring的简单使用步骤,当然还有配置文件的如何编写,Aop的使用等,后边会介绍到。

 

 

           三,Sping框架的优缺点:

                   优点:

  • 轻量级的容器框架,没有侵入性
  • IoC更加容易组合对象之间的关系,通过面向接口进行编程,可以低耦合开发。
  • 易于本地测试(Junit单元测试,不用部署服务器)
  • AOP可以更加容易的进行功能扩展,遵循OCP开发原则。
  • Spring默认对象的创建为单例的,我们不需要再使用单例的设计模式来开发单体类。
  • Spring的集成很强大,另外可以对其他框架的配置进行一元化管理。
  • Spring的声明式事务的方便使用。

 

                  缺点:

                    自我感觉是所有框架共有的,就是开发对设计要求较高,集成测试麻烦,对框架有一定的依赖性。

 

 

         总而言之,Spring框架功能是非常强大的,单独使用可能感觉不是很深,和其他的框架结合使用,就会张显她的魅力了。


   IoCInversion of Control)称之为控制反转,指的是在Spring框架的配置文件中声明对象,由框架负责创建对象,这叫做控制反转。实现方式有两种:DI(Dependency Injection)依赖注入,这也是Spring框架的实现方式,主要学习的也是这个;SLService Locator)服务器定位器实现方式。


              DI依赖注入,就是框架不仅创建了对象,而其还负责初始化相关联的对象的过程。从实现方式上也分为3种方式:


                      a,Interface Injection(接口注入):容器运行时,目标对象实现特定的接口,然后容器通过接口将关联对象注入到目标对象中。这种方式Spring框架不支持,所以了解。


                     b,Setter Injection(set方法注入):容器运行时,通过类属性的set方法将关联对象注入到目标对象中。Spring框架支持,而且是我们开发经常使用的,非常重要。


                     c,Constructor Injection(构造方法注入):容器运行时,通过类的构造方法将关联对象注入到对象中。Spring框架也支持,没有set用的普遍。

 

   好,下边主要总结一下set方法注入和构造方法注入。

 

一,Setter Injection:


    1,当属性为简单字符串时,可以直接增加property标签:例如:

privateString usercode ;

privateString userpswd ;

 

setter方法: 是配置文件中property标签的name属性值的set方法


[html] view plain copy
 print?
  1. <span style="font-size:18px;">          <bean id="loginAction" class="com.bjpowernode.struts2.action.LoginAction" >  
  2.                 <property name="usercode" value="admin"></property>  
  3.                 <property name="userpswd" value="admin"></property>  
  4.             </bean>  
  5. </span>  


 

          2,属性值为引用类型时,通过property中的ref属性来关联对象:

   privateUserService userService;

 

   setter方法

[html] view plain copy
 print?
  1. <span style="font-size:18px;">  <bean id="loginAction" class="com.ljh.struts2.action.LoginAction" >  
  2.         <property name="userService" ref="userService"></property>  
  3.     </bean>  
  4.   
  5. <bean id="userService" class="com.ljh.struts2.service.UserService"></bean>  </span>  


         3,属性为数组类型时,需要在设置属性值时,将多个元素通过逗号隔开,或者利用list标签:

privateString[] names ;

 

setter方法

[html] view plain copy
 print?
  1. <span style="font-size:18px;">      <bean id="loginAction" class="com.ljh.struts2.action.LoginAction" >  
  2.             <property name="names" value="zhang,san,lisi,wangwu"></property>  
  3.         </bean>  
  4. </span>  

如果赋值操作中,需要将逗号作为一个整体,那么需要通过特殊的标签进行赋值

[html] view plain copy
 print?
  1. <span style="font-size:18px;">      <bean id="loginAction" class="com.ljh.struts2.action.LoginAction" >  
  2.             <property name="userService" ref="userService"></property>  
  3.             <property name="names">  
  4.                 <list>  
  5.                     <value>zhang,san</value>  
  6.                     <value>lisi</value>  
  7.                     <value>wangwu</value>                 
  8.                 </list>  
  9.             </property>  
  10.   
  11. </bean></span>  


             4,属性为list集合时,也是使用list标签:

集合如果使用泛型,只能存储相同类型的元素,不使用泛型,可以存储不同类型的元素:

privateList<String> nameList ;

 

setter方法

[html] view plain copy
 print?
  1. <span style="font-size:18px;">              <bean id="loginAction" class="com.ljh.struts2.action.LoginAction" >  
  2.                     <property name="nameList">  
  3.                         <list>  
  4.                             <value>zhang,san</value>  
  5.                             <value>lisi</value>  
  6.                             <value>wangwu</value>                 
  7.                         </list>  
  8.                     </property>  
  9.   
  10. </bean>   </span>  

             5,当属性为map集合时,需要使用map标签:

Private Map map ;

 

setter方法

[html] view plain copy
 print?
  1. <span style="font-size:18px;">      <bean id="loginAction" class="com.ljh.struts2.action.LoginAction" >  
  2.             <property name="map">  
  3.                 <map>  
  4.                     <entry key="hello" value="world"></entry>  
  5.                     <entry key-ref="userService" value-ref="userService"></entry>  
  6.                 </map>  
  7.             </property>  
  8.         </bean>             
  9.   
  10. <bean id="userService" class="com.ljh.struts2.service.UserService"></bean></span>  

              6,属性为Properties集合类型时,需要在设置属性值时,增加props标签

 

privateProperties props ; //继承了Hashtable,是线程安全的

 

setter方法

[html] view plain copy
 print?
  1. <span style="font-size:18px;">          <bean id="loginAction" class="com.bjpowernode.struts2.action.LoginAction" >  
  2.                 <property name="props">  
  3.                     <props>  
  4.                         <prop key="url">jdbc:oracle:thin:@192.168.1.27:1521:ljh</prop>  
  5.                         <prop key="driverName">oracle.jdbc.driver.OracleDriver</prop>  
  6.                         <prop key="username">scott</prop>  
  7.                         <prop key="password">tiger</prop>  
  8.                     </props>  
  9.                 </property>  
  10.   
  11. </bean></span>  

     总结:以上为几种常用属性类型的set注入的写法,set方法注入,框架是先通过默认的无参构造方法进行创建对象,然后进行set注入的。当然如果我们重写了构造方法,没有了无参构造呢?这就需要下边的构造方法注入了。

 

 

       二,Constructor Injection


               1,例如我们声明了有参构造方法,就需要通过次构造方法进行创建对象和关联对象了,利用constructor-arg标签:


[java] view plain copy
 print?
  1. <span style="font-size:18px;">//无参构造方法      public LoginAction(String usercode) {  
  2.             super();  
  3.             this.usercode = usercode;  
  4.   
  5. }</span>  


[java] view plain copy
 print?
  1. <span style="font-size:18px;">      <!--  通过value属性指定其值-->  
  2.         <bean id="loginAction" class="com.ljh.struts2.action.LoginAction" >  
  3.             <constructor-arg value="admin"></constructor-arg>                 
  4.         </bean>  
  5. </span>  

          2,如果我们有多个无参构造方法,里边参数可能不同,顺序可能不同等!怎么办呢?其中框架会根据制定的参数个数,type制定的类型,index制定的先后顺序来查找我们想要的构造方法,来进行初始化和对象关联。


[java] view plain copy
 print?
  1. <span style="font-size:18px;">      <bean id="loginAction" class="com.ljh.struts2.action.LoginAction" >  
  2.             <constructor-arg value="admin" index="0"></constructor-arg>  
  3.             <constructor-arg value="22" type="int" index="1"></constructor-arg>   
  4.   
  5. </bean></span>  


          3,构造方法和set方法同时使用也是可以的,它们两者的标签没有先后顺序问题,框架会先调用带参数的构造方法创建对象,然后构造注入数据,再调用set方法进行属性注入。但是自我感觉这种方法尽量少用。


[html] view plain copy
 print?
  1. <span style="font-size:18px;">      <bean id="loginAction" class="com.bjpowernode.struts2.action.LoginAction" >             
  2.             <constructor-arg value="admin" index="0"></constructor-arg>       
  3.             <constructor-arg value="23" type="int" index="1"></constructor-arg>  
  4.             <property name="userpswd" value="admin"></property>   
  5.   
  6. </bean>   </span>  



          三,自动装配功能,就是框架会自动为我们匹配,利用autowire标签来实现,注意这种自动装配功能不支持简单类型(String,intdate等)他有6个值byName,byType,constructor,autodetect,no,default。从字面类型大概看个差不多吧。简单说一下。


            1byName(根据名称),从Spring环境中获取目标对象时,目标对象中的属性会根据名称在整个Spring环境中查找<bean>标签的id属性值:

<bean id="loginAction"class="com.ljh.struts2.action.LoginAction"autowire="byName" ></bean>

 

           2.byType(根据类型),从Spring环境中获取目标对象时,目标对象中的属性会根据类型在整个spring环境中查找<bean>标签的class属性值:

<bean id="userService"class="com.ljh.struts2.service.UserService"autowire="byType" ></bean>

 

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

 

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

 

          5,no:表示不支持自动装配功能;

 

          6default:表示默认采用上一级标签的自动装配的取值。<beans>标签中的default-autowire属性。如果存在多个配置文件的话,那么每一个配置文件的自动装配方式都是独立的。

     

          分析总结,自动装配就是为了弥补手动装配,如果两者都使用,优先选择手动的。由于自动装配需要在Spring全局环境中搜索,所以性能上会低一些,而且可阅读性较差,所以还是推荐大家使用手动装配功能。

 

 

         综上为Spring框架IOC的基础功能,这样Spring对对象的管理,对彼此之间的解耦起到了非常大的作用,使其优秀的重要条件之一。


Spring AOP详解

一.前言

    在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnblogs.com/xrq730/p/4919025.html

AOP

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

使用"横切"技术,AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

 

AOP核心概念

1、横切关注点

对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

2、切面(aspect)

类是对物体特征的抽象,切面就是对横切关注点的抽象

3、连接点(joinpoint)

被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

4、切入点(pointcut)

对连接点进行拦截的定义

5、通知(advice)

所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类

6、目标对象

代理的目标对象

7、织入(weave)

将切面应用到目标对象并导致代理对象创建的过程

8、引入(introduction)

在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

 

Spring对AOP的支持

Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:

1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了

2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:

1、定义普通业务组件

2、定义切入点,一个切入点可能横切多个业务组件

3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作

所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。

下面给出一个Spring AOP的.xml文件模板,名字叫做aop.xml,之后的内容都在aop.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
            
</beans>
复制代码

基于Spring的AOP简单实现

注意一下,在讲解之前,说明一点:使用Spring AOP,要成功运行起代码,只用Spring提供给开发者的jar包是不够的,请额外上网下载两个jar包:

1、aopalliance.jar

2、aspectjweaver.jar

开始讲解用Spring AOP的XML实现方式,先定义一个接口:

public interface HelloWorld
{
    void printHelloWorld();
    void doPrint();
}

定义两个接口实现类:

复制代码
public class HelloWorldImpl1 implements HelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl1.printHelloWorld()");
    }
    
    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl1.doPrint()");
        return ;
    }
}
复制代码
复制代码
public class HelloWorldImpl2 implements HelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl2.printHelloWorld()");
    }
    
    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl2.doPrint()");
        return ;
    }
}
复制代码

横切关注点,这里是打印时间:

复制代码
public class TimeHandler
{
    public void printTime()
    {
        System.out.println("CurrentTime = " + System.currentTimeMillis());
    }
}
复制代码

有这三个类就可以实现一个简单的Spring AOP了,看一下aop.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler">
                <aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addAllMethod" />
                <aop:after method="printTime" pointcut-ref="addAllMethod" />
            </aop:aspect>
        </aop:config>
</beans>
复制代码

写一个main函数调用一下:

复制代码
public static void main(String[] args)
{
    ApplicationContext ctx = 
            new ClassPathXmlApplicationContext("aop.xml");
        
    HelloWorld hw1 = (HelloWorld)ctx.getBean("helloWorldImpl1");
    HelloWorld hw2 = (HelloWorld)ctx.getBean("helloWorldImpl2");
    hw1.printHelloWorld();
    System.out.println();
    hw1.doPrint();
    
    System.out.println();
    hw2.printHelloWorld();
    System.out.println();
    hw2.doPrint();
}
复制代码

运行结果为:

复制代码
CurrentTime = 1446129611993
Enter HelloWorldImpl1.printHelloWorld()
CurrentTime = 1446129611993

CurrentTime = 1446129611994
Enter HelloWorldImpl1.doPrint()
CurrentTime = 1446129611994

CurrentTime = 1446129611994
Enter HelloWorldImpl2.printHelloWorld()
CurrentTime = 1446129611994

CurrentTime = 1446129611994
Enter HelloWorldImpl2.doPrint()
CurrentTime = 1446129611994
复制代码

看到给HelloWorld接口的两个实现类的所有方法都加上了代理,代理内容就是打印时间

基于Spring的AOP使用其他细节

1、增加一个横切关注点,打印日志,Java类为:

复制代码
public class LogHandler
{
    public void LogBefore()
    {
        System.out.println("Log before method");
    }
    
    public void LogAfter()
    {
        System.out.println("Log after method");
    }
}
复制代码
复制代码
<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        <bean id="logHandler" class="com.xrq.aop.LogHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler" order="1">
                <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addTime" />
                <aop:after method="printTime" pointcut-ref="addTime" />
            </aop:aspect>
            <aop:aspect id="log" ref="logHandler" order="2">
                <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="LogBefore" pointcut-ref="printLog" />
                <aop:after method="LogAfter" pointcut-ref="printLog" />
            </aop:aspect>
        </aop:config>
</beans>
复制代码

测试类不变,打印结果为:

复制代码
CurrentTime = 1446130273734
Log before method
Enter HelloWorldImpl1.printHelloWorld()
Log after method
CurrentTime = 1446130273735

CurrentTime = 1446130273736
Log before method
Enter HelloWorldImpl1.doPrint()
Log after method
CurrentTime = 1446130273736

CurrentTime = 1446130273736
Log before method
Enter HelloWorldImpl2.printHelloWorld()
Log after method
CurrentTime = 1446130273736

CurrentTime = 1446130273737
Log before method
Enter HelloWorldImpl2.doPrint()
Log after method
CurrentTime = 1446130273737
复制代码

要想让logHandler在timeHandler前使用有两个办法:

(1)aspect里面有一个order属性,order属性的数字就是横切关注点的顺序

(2)把logHandler定义在timeHandler前面,Spring默认以aspect的定义顺序作为织入顺序

2、我只想织入接口中的某些方法

修改一下pointcut的expression就好了:

复制代码
<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        <bean id="logHandler" class="com.xrq.aop.LogHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler" order="1">
                <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.print*(..))" />
                <aop:before method="printTime" pointcut-ref="addTime" />
                <aop:after method="printTime" pointcut-ref="addTime" />
            </aop:aspect>
            <aop:aspect id="log" ref="logHandler" order="2">
                <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.do*(..))" />
                <aop:before method="LogBefore" pointcut-ref="printLog" />
                <aop:after method="LogAfter" pointcut-ref="printLog" />
            </aop:aspect>
        </aop:config>
</beans>
复制代码

表示timeHandler只会织入HelloWorld接口print开头的方法,logHandler只会织入HelloWorld接口do开头的方法





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值