天天看点

Spring之面向切面编程(AOP)四种通知面向切面编程(AOP)

面向切面编程(AOP)

面向切面的编程:指很多功能都有重复的代码,把这些重复的代码独立出来实现,再在运行的时候动态加入“切面类代码”。

AOP是一种设计思想,和具体的代码实现无关。

优点:

      A、把共性功能和核心业务功能解耦。

      B、共性代码的复用性

      C、动态删除或增加切面类,不影响原来的代码

Aop的实现

前置通知,后置通知,环绕通知、异常通知

用添加日志文件为例,描述前置通知,后置通知,环绕通知三种通知,即把核心类和切面类组合的方式

以下均是XML配置方式声明切面

1、前置通知

(1)、定义接口 IStudent

public interface IStudent{

   public boolean add(String id,String name);

   public boolean update(String id;String name);

   public boolean delete(String id);

}

注:将方法返回值定义为boolean是为了通过booleanValue()方法将值返回给切面类

(2)、实现接口的实体类StudentDao

public class StudentDao implements IStudent{

   public boolean add(String id,String name){

      System.out.println("正在实现 sava 方法");

      System.out.println("添加学生编号:"+id+" 姓名:"+name);

      return true;

   }

public boolean update(String id,String name){

      System.out.println("正在实现 update 方法");

      System.out.println("修改学生编号:"+id+" 姓名:"+name);

      return true;

   }

public boolean delete(String id){

      System.out.println("正在实现 delete 方法");

      System.out.println("删除学生编号:"+id);

      return true;

   }

}

(3)、定义切面类BeforeAdvice   需要实现MethodBeforeAdvice接口

public class BeforeAdvice implements MethodBeforeAdvice{

   public void befor(Method targetMethod,Object[] methodArgs,Object targetClass){

      String className=targetClass.getClass().getName();//类名

      String methodName=targetMethod.getName();//方法名

      //获取具体的操作时间并记录

      Date date=new Date();

      String currentTime=DateFormat.getDateInstance().format(date);   //获取当前时间并转化成字符串

      String messge="【"+currentTime+“】”+className+"."+methodName+"方法被执行";

      System.out.println(message);

   }

}

注:befor()方法中的参数Method targetMethod表执行的是核心代码的哪个方法,Object[] methodArgs表核心代码中的所有方法,Object targetClass表要找的目标类

(4)、创建配置文件applicationContext.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"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

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

   <bean id="stuPoint" class="com.bean.StudentDao"/><!--核心业务类-->

   <bean id="beforeLogin" class="com.bean.BeforeAdvice"/><!--切面类-->

   <!--导入包中自带的类  是一个代理工厂类    用来组合核心类和切面类-->

   <bean id="studentfactory" class="org.springframework.aop.framewoke.proxyFactoryBean">

      <property name="proxyInterfaces">   <!--核心业务接口-->

         <value>com.bean.Istudent</value>  

      </property>

      <property name="interceptorNames">   <!--切面类-->

          <value>beforeLogin</value>  

      </property>

      <property name="target" ref="stuPoint"/>   <!--核心类-->

   </bean>

</beans>

注:配置文件名最好不变applicationContext.xml,否则需在web.xml中配置

(5)、创建StudentServlet

......

protected void doPost(HttpServletRequest request, HttpServletResponse response) {

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

   IStudent stu=(IStudent)ac.getBean("studentfactory");   //代理工厂类的id

   stu.add("111","张三");

   stu.update("111","李思");

   stu.delete("111");

}

(6)、配置web.xml

<listener>

   <listener-calss>

      org.springframework.web.context.ContextLoaderListener

   </listener-class>

</listener>

<servlet>

      <servlet-name>StudentServlet</servlet-name>

      <servlet-class>com.bean.StudentServlet</servlet-class>

  </servlet>

  <servlet-mapping>

      <servlet-name>StudentServlet</servlet-name>

      <url-pattern>/aop</url-pattern>

  </servlet-mapping>

(7)、将web项目发布到服务器上,在地址栏中输入aop,验证结果

2、后置通知

步骤1、2、5、6、7同上

(3)、修改切面类AfterAdvice,需要实现AfterRetruningAdvice接口

public void afterReturning(Object returnValue,Method targetMehod,Object[] methodArgs,Object targetClass){

   boolean success=((Boolean)returnValue).booleanValue();

   if(success){ 

       String methodName=targetMethod.getName();

       String className=targetClass.getClass().getName();

       Date date=new Date();

       String currentTime=DateFormat.getDateInstance().format(date);

       String str="【"+currentTime+"】"+className+"."+methodName+"方法被执行";

   }  

}

注:Object returnValue表核心业务代码某个方法的返回值

(4)、在applicationContext.xml配置文件中,只需修改切面类即可

3、环绕通知

步骤1、2、5、6、7同上

(3)、切面类ArroundAdvice,需实现MethodInterceptor接口

public class ArroundAdvice implemets MethodInterceptor{

   public Object invoke (MethodInvocation invocation){

      System.out.println("开始执行"+invocation.getMethod().getName+"方法");

      Object obj=invocation.proceed();

      System.out.println("结束执行"+invocation.getMethod().getName+"方法");

      return obj;

   }

}

(4)、相同方式修改配置文件

4、异常通知

需实现org.springframework.aop.ThrowsAdvice接口,不需实现其中方法

public class ThrowTest implemets ThrowsAdvice{

   public void afterThrow([method],[args],[target],subclassofThrowable){

       //异常处理代码

   }

}

注:subclassofThrowable表Throwable的自类,即子类异常

总结:

前置通知:实现MethodBeforeAdvice接口,方法public void before(Method targetMethod, Object[] methodArgs, Object targetClass){}

后置通知:实现AfterReturningAdvice接口,方法public void afterReturning(Object returnValue, Method targetMethod, Object[] methodArgs,Object targetClass)  {}

环绕通知:实现 MethodInterceptor接口,方法public Object invoke(MethodInvocation invocation) {}

异常通知:实现ThrowsAdvice接口,自定义方法public void afterThrowing([Method],[args],[target],subclassOfThrowable)