spring笔记3-AOP

一.概述

AOP:(Aspect Oriented Programming)即:面向切面编程。把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。

二.术语

Joinpoint(连接点):可以被代理增强的方法,即被spring拦截到的点,spring中点即方法,因为spring只支持方法类型的连接点;

Pointcut(切入点):需要或已经被增强的Joinpoint;

Advice(通知):拦截到Joinpoint之后要做的事情即为通知,即要增强的方法;
     通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Target(目标对象):代理的目标对象,或被增强的对象,或Pointcut所在对象;

Proxy(代理对象):对目标对象进行增强后产生的对象;一个类被AOP织入增强后,就产生一个结果代理类。

Weaver(织入):把增强应用到目标对象来创建新的代理对象的过程。将通知应用到切点的过程,称为Weaver;spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

Aspect(切面):切点+通知

Introduction(引介):引介是一种特殊的通知,在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。

三.案例演示:xml--抽取UserServiceImpl中的公共代码

1.导包-4+2/aspects/aop/aopalliance/aspectj.weaver/test

2.建立工程结构:
     huguangqin.com.cnblogs.advice
     huguangqin.com.cnblogs.service
     huguangqin.com.cnblogs.service.serviceImpl
     huguangqin.com.cnblogs.test

3.准备目标对象--要增强的方法所在类UserServiceImpl

  1 package huguangqin.com.cnblogs.service.serviceImpl;
  2     import huguangqin.com.cnblogs.service.UserService;
  3      public class UserServiceImpl implements UserService {
  4          @Override
  5          public void save() {
  6              System.out.println("客户保存了");
  7          }
  8
  9         @Override
 10          public void delete() {
 11              System.out.println("客户删除了");
 12          }
 13
 14         @Override
 15          public void find() {
 16              System.out.println("客户找到了");
 17          }
 18
 19         @Override
 20          public void update() {
 21              System.out.println("客户更新了");
 22          }
 23      }
 24 

4
.准备通知--增强的方法myAdvice

  1 package huguangqin.com.cnblogs.advice;
  2      import org.aspectj.lang.ProceedingJoinPoint;
  3      //通知类
  4     public class MyAdvice {
  5          // 前置
  6         public void before() {
  7              System.out.println("我是前置通知!");
  8          }
  9
 10         // 环绕通知
 11         /*
 12          * spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数
 13          * 在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。
 14          * 该接口中有一个方法proceed(),此方法就相当于method.invoke()
 15           */
 16          public Object around(ProceedingJoinPoint pjp) throws Throwable {
 17              System.out.println("我是环绕通知,前半部分!");
 18              // 执行目标方法
 19             Object proceed = pjp.proceed();
 20              System.out.println("我是环绕通知,后半部分!");
 21              return proceed;
 22          }
 23
 24         // 后置 => 出现异常就不执行的后置通知
 25         public void afterReturning() {
 26              System.out.println("我是后置通知,出现异常就不执行的后置通知!");
 27          }
 28
 29         // 最终通知 => 无论是否出现异常都执行的后置通知
 30         public void after() {
 31              System.out.println("我是最终通知,出现异常仍然执行的后置通知!");
 32          }
 33
 34         // 异常 => 出现异常才执行的通知
 35         public void afterThrowing() {
 36              System.out.println("我是异常通知,出现异常才执行的通知!");
 37          }
 38      }
 39 

5
.编写配置对象applicationContext.xml(位置在src下)

  1  <?xml version="1.0" encoding="UTF-8"?>
  2
  3     <beans
  4      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5      xmlns="http://www.springframework.org/schema/beans"
  6      xmlns:context="http://www.springframework.org/schema/context"
  7      xmlns:aop="http://www.springframework.org/schema/aop"
  8      xsi:schemaLocation="http://www.springframework.org/schema/beans
  9                          http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
 10                          http://www.springframework.org/schema/context
 11                          http://www.springframework.org/schema/context/spring-context-4.2.xsd
 12                          http://www.springframework.org/schema/aop
 13                          http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
 14
 15      <!--配置目标对象  -->
 16      <bean name="userService" class="huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl"></bean>
 17
 18     <!--配置通知对象  -->
 19      <bean name="myAdvice" class="huguangqin.com.cnblogs.advice.MyAdvice"></bean>
 20
 21     <!--将通知织入目标  -->
 22      <!-- 切点表达式
 23         public void huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl.save()
 24          * huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..):
 25              第一个*代表:返回值任意;
 26              第二个*代表:包内所有以ServiceImpl结尾的类;
 27              第三个*代表:类内所有方法
 28             括号内..代表:任意参数
 29      -->
 30      <aop:config>
 31          <!--配置切点  -->
 32          <aop:pointcut expression="execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))" id="mypc"></aop:pointcut>
 33          <!--配置切面  -->
 34          <aop:aspect ref="myAdvice">
 35              <!--前置通知  -->
 36              <aop:before method="before" pointcut-ref="mypc" />
 37              <!--环绕通知  -->
 38              <aop:around method="around" pointcut-ref="mypc" />
 39              <!--最终通知 :出现异常也执行 -->
 40              <aop:after method="after" pointcut-ref="mypc" />
 41              <!--异常通知  -->
 42              <aop:after-throwing method="afterThrowing" pointcut-ref="mypc" />
 43              <!--后置通知:出现异常不执行  -->
 44              <aop:after-returning method="afterReturning" pointcut-ref="mypc" />
 45          </aop:aspect>
 46      </aop:config>
 47      </beans>
 48 

6.测试

  1 package huguangqin.com.cnblogs.test;
  2      import javax.annotation.Resource;
  3      import org.junit.Test;
  4      import org.junit.runner.RunWith;
  5      import org.springframework.test.context.ContextConfiguration;
  6      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  7      import huguangqin.com.cnblogs.service.UserService;
  8
  9     @RunWith(SpringJUnit4ClassRunner.class)
 10      @ContextConfiguration("classpath:applicationContext.xml")
 11      public class Demo {
 12          @Resource(name = "userService")
 13          private UserService us;
 14
 15         @Test
 16          public void save() {
 17              us.save();
 18          }
 19      }
 20 

四.案例演示:注解模式
     与xml模式相比,需修改applicationContext.xml和MyAdvice类
     1.applicationContext.xml

  1  <?xml version="1.0" encoding="UTF-8"?>
  2
  3     <beans
  4      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5      xmlns="http://www.springframework.org/schema/beans"
  6      xmlns:context="http://www.springframework.org/schema/context"
  7      xmlns:aop="http://www.springframework.org/schema/aop"
  8      xsi:schemaLocation="http://www.springframework.org/schema/beans
  9                          http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
 10                          http://www.springframework.org/schema/context
 11                          http://www.springframework.org/schema/context/spring-context-4.2.xsd
 12                          http://www.springframework.org/schema/aop
 13                          http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
 14
 15      <!--配置目标对象  -->
 16      <bean name="userService" class="huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl"></bean>
 17
 18     <!--配置通知对象  -->
 19      <bean name="myAdvice" class="huguangqin.com.cnblogs.advice.MyAdvice"></bean>
 20
 21     <!--将通知织入目标 ,打开注解配置开关 -->
 22      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
 23      </beans>
 24 

2.MyAdvice

  1  package huguangqin.com.cnblogs.advice;
  2
  3     import org.aspectj.lang.ProceedingJoinPoint;
  4      import org.aspectj.lang.annotation.After;
  5      import org.aspectj.lang.annotation.AfterReturning;
  6      import org.aspectj.lang.annotation.AfterThrowing;
  7      import org.aspectj.lang.annotation.Around;
  8      import org.aspectj.lang.annotation.Aspect;
  9      import org.aspectj.lang.annotation.Before;
 10
 11     //通知类
 12     @Aspect
 13      public class MyAdvice {
 14
 15         // 前置
 16         @Before("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
 17          public void before() {
 18              System.out.println("我是前置通知!");
 19          }
 20
 21         // 环绕通知
 22         /*
 23           * spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数
 24          * 在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。
 25          * 该接口中有一个方法proceed(),此方法就相当于method.invoke()
 26           */
 27          @Around("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
 28          public Object around(ProceedingJoinPoint pjp) throws Throwable {
 29              System.out.println("我是环绕通知,前半部分!");
 30              // 执行目标方法
 31             Object proceed = pjp.proceed();
 32              System.out.println("我是环绕通知,后半部分!");
 33              return proceed;
 34          }
 35
 36         // 后置 => 出现异常就不执行的后置通知
 37         @AfterReturning("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
 38          public void afterReturning() {
 39              System.out.println("我是后置通知,出现异常就不执行的后置通知!");
 40          }
 41
 42         // 最终通知 => 无论是否出现异常都执行的后置通知
 43         @After("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
 44          public void after() {
 45              System.out.println("我是最终通知,出现异常仍然执行的后置通知!");
 46          }
 47
 48         // 异常 => 出现异常才执行的通知
 49         @AfterThrowing("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
 50          public void afterThrowing() {
 51              System.out.println("我是异常通知,出现异常才执行的通知!");
 52          }
 53      }
 54 

四.动态代理回顾

1.原生动态代理--必需要一个接口,否则不能使用

a.编写接口

  1  package huguangqin.com.cnblogs.serive;
  2
  3     public interface Service {
  4          void find();
  5      }
  6 

b.编写接口的实现类

  1  package huguangqin.com.cnblogs.seriveImpl;
  2
  3     import huguangqin.com.cnblogs.serive.Service;
  4
  5     public class ServiceImpl implements Service {
  6
  7         @Override
  8          public void find() {
  9              System.out.println("找到了~~");
 10          }
 11
 12     }
 13 

c.创建该动态代理类

  1 package huguangqin.com.cnblogs.proxy;
  2
  3     import java.lang.reflect.InvocationHandler;
  4     import java.lang.reflect.Method;
  5      import java.lang.reflect.Proxy;
  6
  7     import huguangqin.com.cnblogs.serive.Service;
  8      import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
  9
 10     public class MyProxy implements InvocationHandler {
 11
 12         // 目标接口--我需要知道代理哪个接口
 13         private Service target;
 14
 15         // 代理类的有参构造--利用给我的接口生成 这个接口代理类
 16         public MyProxy(Service target) {
 17              super();
 18              this.target = target;
 19          }
 20
 21         // 获取代理对象--输出该接口的代理代象
 22         public Service getServiceProxy() {
 23              return (Service) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(), ServiceImpl.class.getInterfaces(),
 24                      this);
 25          }
 26
 27         @Override
 28          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 29              System.out.println("start transaction");
 30              Object invoke = method.invoke(target, args);
 31             System.out.println("end transaction");
 32              return invoke;
 33          }
 34
 35     }
 36 

d.创建测试类

  1 package huguangqin.com.cnblogs.proxy;
  2
  3     import org.junit.Test;
  4
  5     import huguangqin.com.cnblogs.serive.Service;
  6      import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
  7
  8     public class Demo {
  9
 10         @Test
 11          public void demo() {
 12              // 被代理对象
 13             Service ser = new ServiceImpl();
 14              // 代理工厂
 15             MyProxy mp = new MyProxy(ser);
 16              // 获得代理类
 17             Service proxy = mp.getServiceProxy();
 18              proxy.find();
 19          }
 20      }
 21 

2.CGLIB创建动态代理

c.创建动态代理类

  1 package huguangqin.com.cnblogs.proxy;
  2
  3     import java.lang.reflect.Method;
  4
  5     import org.springframework.cglib.proxy.Enhancer;
  6      import org.springframework.cglib.proxy.MethodInterceptor;
  7      import org.springframework.cglib.proxy.MethodProxy;
  8
  9     import huguangqin.com.cnblogs.serive.Service;
 10      import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
 11
 12     //cglib
 13      public class MyProxy implements MethodInterceptor {
 14
 15         public Service getMyProxy() {
 16              Enhancer en = new Enhancer();
 17              // 指定父类
 18             en.setSuperclass(ServiceImpl.class);
 19              // 设置需要增强的代码
 20             en.setCallback(this);
 21              // 创建代理对象
 22             return (Service) en.create();
 23
 24         }
 25
 26         @Override
 27          // proxy: 代理对象
 28         // arg1: 目标方法对象
 29         // arg2: 目标方法参数
 30         // methodProxy: 代理方法对象
 31         public Object intercept(Object proxy, Method arg1, Object[] arg2, MethodProxy methodProxy) throws Throwable {
 32              System.out.println("start");
 33             // 调用原业务方法
 34             Object invokeSuper = methodProxy.invokeSuper(proxy, arg2);
 35              System.out.println("end");
 36              return invokeSuper;
 37          }
 38
 39     }
 40 

d.测试类

  1  package huguangqin.com.cnblogs.test;
  2
  3     import org.junit.Test;
  4
  5     import huguangqin.com.cnblogs.proxy.MyProxy;
  6      import huguangqin.com.cnblogs.serive.Service;
  7
  8     public class Demo {
  9
 10         @Test
 11          public void demo() {
 12              // 代理工厂
 13             MyProxy mp = new MyProxy();
 14              // 获得代理类
 15             Service proxy = mp.getMyProxy();
 16              proxy.find();
 17          }
 18      }
 19 
时间: 2024-08-09 23:53:19

spring笔记3-AOP的相关文章

Spring笔记(三)AOP前篇之动态代理

AOP思想是将程序中的业务代码与服务代码进行分离,在运行时进行结合.比较强调程序的层次结构,是一种面向切面的编程.而在AOP实现的底层主要用到了动态代理,而动态代理又分为JDK动态代理和CGLIB动态代理,两者的区别是JDK动态代理的实现中业务类必须必须定义接口,而CGLIB没有这个约束,可以说CGLIB更强大: JDK动态代理实现示例: // 业务接口定义 public interface IUnit {     void execute(String msg); } // 业务实现类 pub

Spring笔记(三):Aop详解

一.Aop原理 (一)动态代理 1.详见:java进阶(七):详解JAVA代理 2.主要是Proxy 与 InvocationHandle r接口 (二)Cglib 实现 1.主要是 Enhancer 和 MethodInterceptor 接口 2.实现代码如下: <span style="font-size:18px;"> /** * 利用 cglib 实现 * @param targrt * @return */ public static Object getCgP

Spring 3.0 AOP (一)AOP 术语

关于AOP.之前我已写过一个系列的随笔: <自己实现简单的AOP>,它的关注点在于实现.实现语言是C#,实现方式为 自定义实现 RealProxy 抽象类.重写Invoke方法,以便进行方法调用的拦截.借此实现AOP.感兴趣的园友可以去瞅瞅. 今天.我们来看一下Spring中的AOP,本随笔着重关注AOP术语. 先说一句废话:如果你对AOP不是很熟悉.第一次看到这些术语可能会有点迷惑,不过没有关系.坚持继续向下看,然后再反过来看一遍,有些东西就能恍然大悟了. 连接点(Joinpoint) 连接

spring笔记(一)

这几日,在看spring框架的知识,了解了一下spring的IoC核心,AOP的概念,然后剩下的其实就是Spring对于其他的java服务的封装:ORM,web, JMS,JMX等. 坦白地说,我并没有完全理解spring的结构,首先它的API,我还不是很清楚,现在能至少做个分类.其次,spring框架和ORM之类的框架在做集成时的编程经验,我还没有. 后面的路要一分为二,继续对于spring底层的细节进行学习和了解,其次对于spring和其他组件整合的知识在实践中学习.看书估计不管用了. sp

springMVC+MyBatis+Spring 整合(4) ---解决Spring MVC 对AOP不起作用的问题

解决Spring MVC 对AOP不起作用的问题 分类: SpringMVC3x+Spring3x+MyBatis3x myibaits spring J2EE2013-11-21 11:22 640人阅读 评论(1) 收藏 举报 用的是 SSM3的框架 Spring MVC 3.1 + Spring 3.1 + Mybatis3.1第一种情况:Spring MVC 和 Spring 整合的时候,SpringMVC的springmvc.xml文件中 配置扫描包,不要包含 service的注解,S

spring中的aop注解(整合junit测试)

使用spring中的aop前先来了解一下spring中aop中的一些名词 Joimpoint(连接点):目标对象中,所有可能增强的方法 PointCut(切入点):目标对象,已经增强的方法 Advice(通知/增强):增强的代码 Target(目标对象):被代理对象 Weaving(织入):将通知应用到切入点的过程 Proxy(代理):将通知织入到目标对象之后,形成代理对象 aspect(切面):切入点+通知 一:不使用spring的aop注解 以javaEE中的service层为例 UserS

Spring Boot学习——AOP编程的简单实现

首先应该明白一点,AOP是一种编程范式,是一种程序设计思想,与具体的计算机编程语言无关,所以不止是Java,像.Net等其他编程语言也有AOP的实现方式.AOP的思想理念就是将通用逻辑从业务逻辑中分离出来. 本文将通过一个HTTP请求的例子简单的讲解Spring Boot中AOP的应用,步骤如下: 第一步,添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr

Spring 笔记

1, 新建包或导入工程错误提示: The type javax.servlet.ServletContext cannot be resolved. It is indirectly referenced from required .class files. 解决方法:在安装的tomcat下的lib目录里面找到servlet-api.jar包,导入项目下的lib文件夹中即可. 2,Could not load the Tomcat server configuration at /Server

Spring核心框架 - AOP的原理及源码解析

一.AOP的体系结构 如下图所示:(引自AOP联盟) 层次3语言和开发环境:基础是指待增加对象或者目标对象:切面通常包括对于基础的增加应用:配置是指AOP体系中提供的配置环境或者编织配置,通过该配置AOP将基础和切面结合起来,从而完成切面对目标对象的编织实现. 层次2面向方面系统:配置模型,逻辑配置和AOP模型是为上策的语言和开发环境提供支持的,主要功能是将需要增强的目标对象.切面和配置使用AOP的API转换.抽象.封装成面向方面中的逻辑模型. 层次1底层编织实现模块:主要是将面向方面系统抽象封

Spring中的AOP(五)——在Advice方法中获取目标方法的参数

摘要: 本文介绍使用Spring AOP编程中,在增强处理方法中获取目标方法的参数,定义切点表达式时使用args来快速获取目标方法的参数. 获取目标方法的信息 访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点.JoinPoint里包含了如下几个常用的方法: Object[] getArgs:返回目标方法的参数 Signature getSignature:返回目标方法的签名 Ob