SSH框架之Spring

概述

SSH框架之Spring_第1张图片

  • 核心容器:核心容器提供 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。

控制反转(IOC)

IOC是Inversion of Control

IOC理解

1、未使用IOC,软件系统中紧耦合的对象
SSH框架之Spring_第2张图片


2、IOC解耦过程

IOC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦

由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系

IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用

3、拿掉IoC容器后的系统
SSH框架之Spring_第3张图片

控制反转(IOC)到底为什么要起这么个名字?

软件系统在没有引入IOC容器之前,如图1所示,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。

软件系统在引入IOC容器之后,这种情形就完全改变了,如图3所示,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。

通过前后的对比,我们不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。

依赖注入(DI)

既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

对象A依赖于对象B,当对象 A需要用到对象B的时候,IOC容器就会立即创建一个对象B送给对象A。IOC容器就是一个对象制造工厂,你需要什么,它会给你送去,你直接使用就行了,而再也不用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切全部由IOC容器包办。

在传统的实现中,由程序内部代码来控制组件之间的关系。我们经常使用new关键字来实现两个组件之间关系的组合,这种实现方式会造成组件之间耦合。IOC很好地解决了该问题,它将实现组件间关系从程序内部提到外部容器,也就是说由容器在运行期将组件间的某种依赖关系动态注入组件中。

IOC实现原理

IOC中最基本的技术就是“反射(Reflection)”编程

有关反射的概念和用法,大家应该都很清楚,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象

我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。

使用IOC框架应该注意什么

  • 第一、软件系统中由于引入了第三方IOC容器,生成对象的步骤变得有些复杂,本来是两者之间的事情,又凭空多出一道手续,所以,我们在刚开始使用IOC框架的时候,会感觉系统变得不太直观。
  • 第二、由于IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗。如果你要追求运行效率的话,就必须对此进行权衡。
  • 第三、具体到IOC框架产品(比如:Spring)来讲,需要进行大量的配制工作,比较繁琐,对于一些小的项目而言,客观上也可能加大一些工作成本。

自定义Spring实现

首先,我们定义一个Bean类,这个类用来存放一个Bean拥有的属性

/* Bean Id */  
    private String id;  
    /* Bean Class */  
    private String type;  
    /* Bean Property */  
    private Map<String, Object> properties = new HashMap<String, Object>(); 

一个Bean包括id,type,和Properties。

接下来Spring 就开始加载我们的配置文件了,将我们配置的信息保存在一个HashMap中,HashMap的key就是Bean 的 Id ,HasMap 的value是这个Bean

<bean id="test" class="Test">  
        <property name="testMap">  
            <map>  
                <entry key="a">  
                    <value>1</value>  
                </entry>  
                <entry key="b">  
                    <value>2</value>  
                </entry>  
            </map>  
        </property>  
    </bean>  

Spring是怎样保存上面的配置呢?,代码如下:

if (beanProperty.element("map") != null) {  
                    Map<String, Object> propertiesMap = new HashMap<String, Object>(); 
                    Element propertiesListMap = (Element) beanProperty  
                            .elements().get(0); 
                    Iterator<?> propertiesIterator = propertiesListMap  
                            .elements().iterator(); 
                    while (propertiesIterator.hasNext()) {  
                        Element vet = (Element) propertiesIterator.next(); 
                        if (vet.getName().equals("entry")) {  
                            String key = vet.attributeValue("key"); 
                            Iterator<?> valuesIterator = vet.elements()  
                                    .iterator(); 
                            while (valuesIterator.hasNext()) {  
                                Element value = (Element) valuesIterator.next(); 
                                if (value.getName().equals("value")) {  
                                    propertiesMap.put(key, value.getText()); 
                                }  
                                if (value.getName().equals("ref")) {  
                                    propertiesMap.put(key, new String[] { value  
                                            .attributeValue("bean") }); 
                                }  
                            }  
                        }  
                    }  
                    bean.getProperties().put(name, propertiesMap); 
                }  

接下来就进入最核心部分了,让我们看看Spring 到底是怎么依赖注入的吧,其实依赖注入的思想也很简单,它是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。让我们看看具体它是怎么做的吧。
首先实例化一个类,像这样

public static Object newInstance(String className) {  
        Class<?> cls = null;  
        Object obj = null;  
        try {  
            cls = Class.forName(className);  
            obj = cls.newInstance();  
        } catch (ClassNotFoundException e) {  
            throw new RuntimeException(e);  
        } catch (InstantiationException e) {  
            throw new RuntimeException(e);  
        } catch (IllegalAccessException e) {  
            throw new RuntimeException(e);  
        }  
        return obj;  
    } 

接着它将这个类的依赖注入进去,像这样

public static void setProperty(Object obj, String name, String value) {  
        Class<? extends Object> clazz = obj.getClass();  
        try {  
            String methodName = returnSetMthodName(name);  
            Method[] ms = clazz.getMethods();  
            for (Method m : ms) {  
                if (m.getName().equals(methodName)) {  
                    if (m.getParameterTypes().length == 1) {  
                        Class<?> clazzParameterType = m.getParameterTypes()[0];  
                        setFieldValue(clazzParameterType.getName(), value, m,  
                                obj);  
                        break;  
                    }  
                }  
            }  
        } catch (SecurityException e) {  
            throw new RuntimeException(e);  
        } catch (IllegalArgumentException e) {  
            throw new RuntimeException(e);  
        } catch (IllegalAccessException e) {  
            throw new RuntimeException(e);  
        } catch (InvocationTargetException e) {  
            throw new RuntimeException(e);  
        }  
}  

最后它将这个类的实例返回给我们,我们就可以用了。我们还是以Map为例看看它是怎么做的,我写的代码里面是创建一个HashMap并把该HashMap注入到需要注入的类中,像这样

if (value instanceof Map) {  
                Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()  
                        .iterator();  
                Map<String, Object> map = new HashMap<String, Object>();  
                while (entryIterator.hasNext()) {  
                    Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();  
                    if (entryMap.getValue() instanceof String[]) {  
                        map.put((String) entryMap.getKey(),  
                                getBean(((String[]) entryMap.getValue())[0]));  
                    }  
                }  
                BeanProcesser.setProperty(obj, property, map);  
            }  

Spring实际应用配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

<bean id="createCreditCard" -->define createCreditCard definition
class="springexample.creditcardaccount.CreateCreditCardAccount">
<property name="creditRatingInterface">-->inject creditRatingInterface dependency  via creditRating reference bean(依赖注入)
<ref bean="creditRating" />
</property>
<property name="creditLinkingInterface">">-->inject creditLinkingInterface dependency  via creditLinking reference bean(依赖注入)
<ref bean="creditLinking" />
</property>
<property name="emailInterface">">">-->inject emailInterface dependency  via email reference bean
<ref bean="email" />
/property>
</bean>

<bean id="creditLinking" class="springexample.creditlinking.CreditLinking">
<property name="url">
<value>http://localhost/creditLinkService</value>-->set url property value (赋值)
</property>
</bean>

<bean id="creditRating" class="springexample.creditrating.CreditRating">
</bean>

<bean id="email" class="springexample.email.Email">
<property name="smtpHost">
<value>localhost</value>>-->set smpHtpHost property value 
</property>
<property name="fromEmail">
<value>[email protected]</value>
</property>
<property name="userId">
<value>myuserid</value>
</property>
<property name="password">
<value>mypassword</value>
</property>
</bean>
</beans>

Spring AOP

AOP(Aspect Orient Programming),也就是面向方面编程,作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表;而动态代理则以 Spring AOP 为代表。

其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。

AOP存在的价值

现在假设系统中有 3 段完全相似的代码,这些代码通常会采用“复制”、“粘贴”方式来完成,通过这种“复制”、“粘贴”方式开发出来的软件如图 1 所示。

SSH框架之Spring_第4张图片

        图 1.多个地方包含相同代码的软件

看到如图 1 所示的示意图,可能有的读者已经发现了这种做法的不足之处:如果有一天,图 1 中的深色代码段需要修改,那是不是要打开 3 个地方的代码进行修改?如果不是 3 个地方包含这段代码,而是 100 个地方,甚至是 1000 个地方包含这段代码段,那会是什么后果?
为了解决这个问题,我们通常会采用将如图 1 所示的深色代码部分定义成一个方法,然后在 3 个代码段中分别调用该方法即可。在这种方式下,软件系统的结构如图 2 所示。


图 2 通过方法调用实现系统功能

对于如图 2 所示的软件系统,如果需要修改深色部分的代码,只要修改一个地方即可,不管整个系统中有多少地方调用了该方法,程序无须修改这些地方,只需修改被调用的方法即可——通过这种方式,大大降低了软件后期维护的复杂度。

对于如图 2 所示的方法 1、方法 2、方法 3 依然需要显式调用深色方法,这样做能够解决大部分应用场景。但对于一些更特殊的情况:应用需要方法 1、方法 2、方法 3 彻底与深色方法分离——方法 1、方法 2、方法 3 无须直接调用深色方法,那如何解决?

因为软件系统需求变更是很频繁的事情,系统前期设计方法 1、方法 2、方法 3 时只实现了核心业务功能,过了一段时间,我们需要为方法 1、方法 2、方法 3 都增加事务控制;又过了一段时间,客户提出方法 1、方法 2、方法 3 需要进行用户合法性验证,只有合法的用户才能执行这些方法;又过了一段时间,客户又提出方法 1、方法 2、方法 3 应该增加日志记录;又过了一段时间,客户又提出……面对这样的情况,我们怎么办?通常有两种做法:

  • 根据需求说明书,直接拒绝客户要求。
  • 拥抱需求,满足客户的需求。

第一种做法显然不好,客户是上帝,我们应该尽量满足客户的需求。通常会采用第二种做法,那如何解决呢?是不是每次先定义一个新方法,然后修改方法 1、方法 2、方法 3,增加调用新方法?这样做的工作量也不小啊!我们希望有一种特殊的方法:我们只要定义该方法,无须在方法 1、方法 2、方法 3 中显式调用它,系统会“自动”执行该特殊方法。

上面想法听起来很神奇,甚至有一些不切实际,但其实是完全可以实现的,实现这个需求的技术就是 AOP。AOP 专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP 已经成为一种非常常用的解决方案。

基本概念

  1. 切面(Aspect)
    官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”,“切面”在ApplicationContext中< aop:aspect >来配置。
  2. 连接点(Joinpoint)
    程序执行过程中的某一行为。
  3. 通知(Advice)
    “切面”对于某个“连接点”所产生的动作,一个“切面”可以包含多个“Advice”。Advice共有如下5种类型:

A. 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。xml中在< aop:aspect>里面使用< aop:before>元素进行声明;

B 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。xml中在< aop:aspect>里面使用< aop:after>元素进行声明

C 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。xml中在< aop:aspect>里面使用< after-returning>元素进行声明。

D 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。xml中在< aop:aspect>里面使用< aop:around>元素进行声明。例如,TestAspect中的doAround方法。

E 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。xml中在< aop:aspect>里面使用< aop:after-throwing>元素进行声明。

通知执行顺序:前置通知→环绕通知连接点之前→连接点执行→环绕通知连接点之后→返回通知→后通知 →(如果发生异常)异常通知→后通知

匹配语法

  • * 匹配任何数量字符;
  • .. 匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
  • +匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

常用的匹配种类

1. 类

注解 类名  

注解:可选,类上持有的注解,如@Deprecated;
类名:必填,任何类的完整名称

2 方法

注解 修饰符 返回值类型 类名 方法名(参数列表) 异常列表 

注解:可选,方法上持有的注解,如@Deprecated;
修饰符:可选,如public、protected;
返回值类型:必填,可以是任何类型模式;“*”表示所有类型;
类名:可选,任何类的完整名称;
方法名:必填,可以使用“*”进行模式匹配;
参数列表:“()”表示方法没有任何参数;“(..)”表示匹配接受任意个参数的方法,“(..,java.lang.String)”表示匹配接受java.lang.String类型的参数结束,且其前边可以接受有任意个参数的方法;“(java.lang.String,..)” 表示匹配接受java.lang.String类型的参数开始,且其后边可以接受任意个参数的方法;“(*,java.lang.String)” 表示匹配接受java.lang.String类型的参数结束,且其前边接受有一个任意类型参数的方法;
异常列表:可选,以“throws 异常全限定名列表”声明,异常全限定名列表如有多个以“,”分割,如throws java.lang.IllegalArgumentException, java.lang.ArrayIndexOutOfBoundsException。

参考:
http://blog.csdn.net/wangpeng047/article/details/8556800

AOP日志实现实例

在java开发中日志的管理有很多种。我一般会使用过滤器,或者是Spring的拦截器进行日志的处理。如果是用过滤器比较简单,只要对所有的.do提交进行拦截,然后获取action的提交路径就可以获取对每个方法的调用。然后进行日志记录。使用过滤器的好处是可以自己选择性的对某一些方法进行过滤,记录日志。但是实现起来有点麻烦。

另外一种就是使用Spring的AOP了。这种方式实现起来非常简单,只要配置一下配置文件就可以了。可是这种方式会拦截下所有的对action的每个操作。使得效率比较低。不过想做详细日志这个方法还是非常好的。下面我就介绍一下使用Spring AOP进行日志记录的方式。

第一种。Spring AOP对普通类的拦截操作
首先我们要写一个普通类,此类作为日志记录类。 比如

package chen.hui.log  
 public classs MyLog{  
           //在类里面写方法,方法名诗可以任意的。此处我用标准的before和after来表示 
          public void before(){  
                    System.out.println("被拦截方法调用之前调用此方法,输出此语句");  
          }  
          public void after(){  
                      System.out.println("被拦截方法调用之后调用此方法,输出此语句");  
          }  
}  
 其次我们在写一个类作为被拦截类(Spring的AOP就是拦截这个类里面的方法)  
 package chen.hui.log  
 public class Test{//此类中方法可以写任意多个。我只写一个 
              public void test(){  
                    Sytem.out.println("测试类的test方法被调用");  
              }  
 }

最后进行配置文件的编写。在Spring的配置文件中我们需要进行几句话的配置

<bean id="testLog" class="chen.hui.log.MyLog"></bean> <!--将日志类注入到bean中。-->  

       <aop:config>  
                   <aop:aspect id="b" ref="testLog"><!--调用日志类-->  
                  <aop:pointcut id="log" expression="execution(* chen.hui.log.*.*(..))"/><!--配置在log包下所有的类在调用之前都会被拦截-->  
                  <aop:before pointcut-ref="log" method="before"/><!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的before方法-->  
                  <aop:after pointcut-ref="log" method="after"/>><!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的after方法-->  

                  </aop:aspect>  

       </aop:config>  

到此处整个程序完成,在MyLog类里面的before和after方法添加日志逻辑代码就可以完成日志的管理。以上是对普通类的管理,如果只想拦截某一个类。只要把倒数第二个 * 改成类名就可以了。

第二:使用Spring AOP对action做日志管理
如果是想拦截action对action做日志管理,基本和上面差不多,但是要注意。以下几点
首先还是要写一个普通类,不过此类中的方法需要传入参数。 比如

package chen.hui.log  
import org.aspectj.lang.JoinPoint;  
 public classs MyLog{  
           //在类里面写方法,方法名诗可以任意的。此处我用标准的before和after来表示 
            //此处的JoinPoint类可以获取,action所有的相关配置信息和request等内置对象。 
          public void before(JoinPoint joinpoint){  
                    joinpoint.getArgs();//此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象 
                    System.out.println("被拦截方法调用之前调用此方法,输出此语句");  
          }  
          public void after(JoinPoint joinpoint){  
                      System.out.println("被拦截方法调用之后调用此方法,输出此语句");  
          }  
}  

其次我们在写一个action类作为被拦截类(Spring的AOP就是拦截这个类里面的方法)

package chen.hui.log  
public class LoginAction{//此类中方法可以写任意多个。我只写一个 
             public void test(){  
                   Sytem.out.println("测试类的test方法被调用");  
             }  
} 

最后进行配置文件的编写。在Spring的配置文件中我们需要进行几句话的配置

<bean id="testLog" class="chen.hui.log.MyLog"></bean> <!--将日志类注入到bean中。-->  

    <aop:config>  
                <aop:aspect id="b" ref="testLog"><!--调用日志类-->  
               <aop:pointcut id="log" expression="execution(* chen.hui.log.*.*(..))"/><!--配置在log包下所有的类在调用之前都会被拦截-->  
               <aop:before pointcut-ref="log" method="before"/><!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的before方法-->  
               <aop:after pointcut-ref="log" method="after"/>><!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的after方法-->  

               </aop:aspect>  

    </aop:config>  

除了参数外其他地方基本和普通类相似。
需要注意的是:普通类可以监控单一的类,而action在配置文件中只能到包名而不能到action的类名。不然会报错。就是说如果要记录日志就要记录所有的action而不能记录其中一个,这是我试了好久得出的结果。

.实现登陆和日志管理(使用Spring AOP)

  • LoginService LogService TestMain
  • 用Spring 管理 LoginService 和 LogService 的对象
  • 确定哪些连接点是切入点,在配置文件中
  • 将LogService封装为通知
  • 将通知植入到切入点
<aop:config>
    <aop:pointcut expression="execution(* cn.com.spring.service.impl.*.*(..))" id="myPointcut"/>
    <!--将哪个-->
    <aop:aspect id="dd" ref="logService">
      <aop:before method="log" pointcut-ref="myPointcut"/>
    </aop:aspect>
</aop:config>

execution(* * cn.com.spring.service.impl..(..))

  • *所有的修饰符
  • *所有的返回类型
  • *所有的类名
  • *所有的方法名
  • ..所有的参数名

1.ILoginService.java

package cn.com.spring.service;

public interface ILoginService {
    public boolean login(String userName, String password);
}

2.LoginServiceImpl.java

package cn.com.spring.service.impl;

import cn.com.spring.service.ILoginService;

public class LoginServiceImpl implements ILoginService {

    public boolean login(String userName, String password) {
        System.out.println("login:" + userName + "," + password);
        return true;
    }

}

3.ILogService.java

package cn.com.spring.service;

import org.aspectj.lang.JoinPoint;

public interface ILogService {
    //无参的日志方法
    public void log();
    //有参的日志方法
    public void logArg(JoinPoint point);
    //有参有返回值的方法
    public void logArgAndReturn(JoinPoint point,Object returnObj);
}

4.LogServiceImpl.java

package cn.com.spring.service.impl;

import org.aspectj.lang.JoinPoint;

import cn.com.spring.service.ILogService;

public class LogServiceImpl implements ILogService {

    @Override
    public void log() {
        System.out.println("*************Log*******************");
    }

    //有参无返回值的方法
    public void logArg(JoinPoint point) {
        //此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象
        Object[] args = point.getArgs();
        System.out.println("目标参数列表:");
        if (args != null) {
            for (Object obj : args) {
                System.out.println(obj + ",");
            }
            System.out.println();
        }
    }

    //有参并有返回值的方法
    public void logArgAndReturn(JoinPoint point, Object returnObj) {
        //此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象
        Object[] args = point.getArgs();
        System.out.println("目标参数列表:");
        if (args != null) {
            for (Object obj : args) {
                System.out.println(obj + ",");
            }
            System.out.println();
            System.out.println("执行结果是:" + returnObj);
        }
    }
}

5.applicationContext.java

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <bean id="logService" class="cn.com.spring.service.impl.LogServiceImpl"></bean>
    <bean id="loginService" class="cn.com.spring.service.impl.LoginServiceImpl"></bean>

    <aop:config>
        <!-- 切入点 -->
        <aop:pointcut  expression="execution(* cn.com.spring.service.impl.LoginServiceImpl.*(..))" id="myPointcut" />
        <!-- 切面: 将哪个对象中的哪个方法,织入到哪个切入点 -->
        <aop:aspect id="dd" ref="logService">
            <!-- 前置通知 <aop:before method="log" pointcut-ref="myPointcut" /> <aop:after method="logArg" pointcut-ref="myPointcut"> -->
            <aop:after-returning method="logArgAndReturn" returning="returnObj" pointcut-ref="myPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

6.TestMain.java

public class TestMain {
public static void testSpringAOP(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("app*.xml");

        ILoginService loginService = (ILoginService)ctx.getBean("loginService");
        loginService.login("zhangsan", "12344");
}
public static void main(String[] args) {
testSpringAOP();
}
}

7.输出结果:

login:zhangsan,12344

目标参数列表:

zhangsan,

12344,

执行结果是:true

解析:

1.先调用了login()方法System.out.println(“login:” + userName + “,” + password);

2.再调用了logArgAndReturn()方法输出了日志,并且返回了login()方法是否成功

System.out.println("目标参数列表:");
        if (args != null) {
            for (Object obj : args) {
                System.out.println(obj + ",");
            }
            System.out.println();
            System.out.println("执行结果是:" + returnObj);
        }

你可能感兴趣的:(spring,框架,ssh)