Spring AOP
2015-09-14 20:51
239 查看
AOP
AOP 的定义
AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.
在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.
AOP 的好处
每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级业务模块更简洁, 只包含核心业务代码.
切面(Aspect) 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
通知(Advice)
切面必须要完成的工作目标(Target)
被通知的对象代理(Proxy)
向目标对象应用通知之后创建的对象连接点(Joinpoint)
程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 ArithmethicCalculator#add() 方法执行前的连接点,执行点为 ArithmethicCalculator#add(); 方位为该方法执行前的位置切点(pointcut)
每个类都拥有多个连接点:例如 ArithmethicCalculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。原理
动态代理代理设计模式
代理设计模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上.示例代码(使用动态代理自己实现的日志代理类)
package com.weixuan.springaop; public interface Calculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); } package com.weixuan.springaop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; public class CalculatorLoggingProxy { /** * 要代理的对象 */ private Calculator calculator; public CalculatorLoggingProxy(Calculator calculator) { this.calculator = calculator; } public Calculator getLoggingProxy() { Calculator proxy = null; /** * 代理对象有哪一个类加载器来进行加载 */ ClassLoader classLoader = calculator.getClass().getClassLoader(); /** * 代码对象有哪些方法 */ Class[] interfaces = new Class[] { Calculator.class }; /** * 当调用代理对象的方法时,执行的代码 */ InvocationHandler invocationHandler = new InvocationHandler() { /** * @param proxy * 正在返回的对象,一般情况下,不使用 * @param method * 正在被调用的方法 * @param args * 调用方法时传入的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /** * 日志 */ System.out.println("The mathod " + method.getName() + " begins with " + Arrays.asList(args)); /** * 执行 */ Object result = method.invoke(calculator, args); /** * 日志 */ System.out.println("The mathod " + method.getName() + " ends with " + result); return result; } }; return proxy = (Calculator) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); } } package com.weixuan.springaop; public class Client { public static void main(String[] args) { Calculator calculator = new CalculatorImpl(); //System.out.println("----> " + calculator.div(4, 2)); Calculator proxy = new CalculatorLoggingProxy(calculator).getLoggingProxy(); proxy.add(2, 3); } }
使用spring aop的注解
package com.weixuan.springsop.aspect; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * 把这个类声明为一个切面 * * @author Nicholas * 1. 把该类放入IOC容器 @compont * 2. 添加注解 @aspect */ @Component @Aspect public class LoggingAspect { /** * 声明该方法是一个前置通知 joinpoint 切入点 */ @Before("execution(public int com.weixuan.springsop.inter.Calculator.*(int , int ))") public void beforeMessage(JoinPoint joinpoint) { String methodName = joinpoint.getSignature().getName(); List<Object> args = Arrays.asList(joinpoint.getArgs()); System.out.println("The method " + methodName + " begin with " + args); } } package com.weixuan.springsop.impl; import org.springframework.stereotype.Component; import com.weixuan.springsop.inter.Calculator; @Component public class CalculatorImpl implements Calculator { @Override public int add(int i, int j) { return i + j; } @Override public int sub(int i, int j) { return i - j; } @Override public int mul(int i, int j) { return i * j; } @Override public int div(int i, int j) { if (j != 0) return i / j; return 0; } } package com.weixuan.springsop.client; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.weixuan.springsop.inter.Calculator; public class Main { public static void main(String[] args) { // 1. 创建ioc容器 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/weixuan/springsop/config/application-context.xml"); // 2. 获取实例 Calculator calculator = applicationContext.getBean(Calculator.class); // 3. 使用 System.out.println(calculator.add(2, 4)); } }
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <!-- 配置自动扫描的包 --> <context:component-scan base-package="com.weixuan.springsop"></context:component-scan> <!-- 使aspect注解起作用 ,自动为匹配的类生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
各种通知
package com.weixuan.springsop.aspect; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * 把这个类声明为一个切面 * * @author Nicholas 1. 把该类放入IOC容器 @compont 2. 添加注解 @aspect */ @Component @Aspect public class LoggingAspect { /** * 声明该方法是一个前置通知 joinpoint 切入点 */ @Before("execution(public int com.weixuan.springsop.inter.Calculator.*(int , int ))") public void beforeMessage(JoinPoint joinpoint) { String methodName = joinpoint.getSignature().getName(); List<Object> args = Arrays.asList(joinpoint.getArgs()); System.out.println("The method " + methodName + " begin with " + args); } /** * 无论是否有异常,都执行 还不能访问目标方法的返回结果,返回结果要在返回通知中才能访问 * * @param joinpoint */ @After("execution(public int com.weixuan.springsop.inter.Calculator.*(int , int ))") public void afterMessage(JoinPoint joinpoint) { String methodName = joinpoint.getSignature().getName(); List<Object> args = Arrays.asList(joinpoint.getArgs()); System.out.println("The method " + methodName + " end with " + args); } /** * 返回通知 * * @param joinpoint * 在方法正常返回的通知 */ @AfterReturning(value = "execution(public int com.weixuan.springsop.inter.Calculator.*(int , int ))", returning = "result") public void returnMessage(JoinPoint joinpoint, Object result) { String methodName = joinpoint.getSignature().getName(); System.out.println("The method " + methodName + " return with " + result); } /** * 返回通知 * * @param joinpoint * 在方法正常返回的通知 */ @AfterThrowing(value = "execution(public int com.weixuan.springsop.inter.Calculator.*(int , int ))", throwing = "exception") public void throwingMessage(JoinPoint joinpoint, Exception exception) { String methodName = joinpoint.getSignature().getName(); System.out.println("The method " + methodName + " occurs exception " + exception); } /** * 环绕通知 类似于 动态代理的全过程 这个类型参数可以决定是否执行目标方法,必须有返回值。 * * @param ProceedingJoinPoint * 在方法正常返回的通知s */ @Around(value = "execution(public int com.weixuan.springsop.inter.Calculator.*(int , int ))") public Object aroundMessage(ProceedingJoinPoint proceedingJoinPoint) { System.out.println("The method "); Object result = null; try { result = proceedingJoinPoint.proceed(); } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; } }
切面的优先级
多个切面,那个先执行?使用@order(1..n)指定优先级,值越小,优先级越高
@Component @Aspect @Order(1) public class LoggingAspect {}
相关文章推荐
- 一个jar包里的网站
- 一个jar包里的网站之文件上传
- 一个jar包里的网站之返回对媒体类型
- spring+html5实现安全传输随机数字密码键盘
- Spring中属性注入详解
- struts2 spring整合fieldError问题
- spring的jdbctemplate的crud的基类dao
- 读取spring配置文件的方法(spring读取资源文件)
- java实现简单美女拼图游戏
- java基本教程之线程休眠 java多线程教程
- JSP开发中在spring mvc项目中实现登录账号单浏览器登录
- 基于Spring框架的Shiro配置方法
- Spring MVC中上传文件实例
- 实例讲解Java的Spring框架中的AOP实现
- 解析Java中如何获取Spring中配置的bean
- Spring的注解配置与XML配置之间的比较
- java Spring整合Freemarker的详细步骤
- Java 二维码,QR码,J4L-QRCode 的资料整理
- java当中的定时器的4种使用方式
- java中 spring 定时任务 实现代码