赞
踩
Aop:: 面向切面编程 在不影响核心代码的前提下,可以在任意位置添加非核心代码。
AOP基于IOC基础,是对OOP的有益补充。
通过动态代理实现核心业务和非核心业务的一种抽取。比较麻烦。 可以使用spring 的aop来完成代理
AOP常用的术语有:通知、切点、和连接点
通知(Advice):定义了切面是什么以及何时使用
Spring有5种通知类型:
Before——前置通知:在方法调用之前调用通知
After——返回通知:在方法完成之后调用通知,无论方法是否执行成功;
After-returing——正常返回通知:在方法成功执行之后调用;
After-throwing——异常返回通知:在方法抛出异常时调用通知;
Around——环绕通知:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
连接点(Joinpoint):是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时(程序中的任意地方)。
切点(pointcut):一个切面并不需要通知应用的所有连接点。切点有助于缩小切面所通知连接点的范围。通常使用明确的类和方法来定义这些切点,或是利用正则表达式定义匹配的类和方法名称模式来指定这些切点。对比:连接点相当于数据库中的记录,切点相当于查询条件
切面(Aspect):通知和切点的结合,通知和切点共同定义了关于切面的全部内容——它是什么,在何时和何处完成其功能。被模块化的特殊对象。如日志类。
public class MyProxy { // 目标对象 private ArithmeticCalculator target; //构造函数 public MyProxy(ArithmeticCalculator a) { this.target = a; } //jdk子代的原生动态代理 必须基于接口 // ClassLoader loader,被代理对象的加载器 // Class<?>[] interfaces, 被代理对象实现的借口 // InvocationHandler h: 被代理对象那些相位需要被代理 public ArithmeticCalculator getProxyInstance() { ClassLoader classLoader = target.getClass().getClassLoader(); Class<?>[] interfaces = {ArithmeticCalculator.class}; InvocationHandler h = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("BBB"+method.getName()+ Arrays.asList(args)); Object result = method.invoke(target, args); return result; } }; return (ArithmeticCalculator) Proxy.newProxyInstance(classLoader, interfaces, h); }
(1)把相关spring的依赖加入
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.9.RELEASE</version> </dependency> <!--切面依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.9.RELEASE</version> </dependency> </dependencies>
(2)创建一个切面类
Aspect支持 5 种类型的通知注解:
@Before: 前置通知, 在方法执行之前执行
@After: 后置通知, 在方法执行之后执行
@AfterRunning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@Around: 环绕通知, 围绕着方法执行
//日志切面类 @Component @Aspect//表示该类为切面类 删除某一个记录 添加日志 操作日志 事务 (1)开启事务 (2)提交事务 (3)事务回滚 public class LogAspect { // public double返回类型 // 表示在这个方法前执行次方法 // @Before(value = "execution(public double com.zz.proxy.after.ArithmeticCalculatorImpl.add(double,double))") // 表示com.zz.proxy.after下的所有类,所有的方法,所有的参数 // 前置通知 @Before(value = "execution(* com.zz.proxy.after.*.*(..))") public void before(JoinPoint joinPoint) { // 得到方法对象 String name = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("AAA--->" + name + "method begin with" + Arrays.asList(args)); } // 后置通知 finally @After(value = "execution(* com.zz.proxy.after.*.*(..))") public void after(JoinPoint joinPoint) { // 得到对象的方法 String name = joinPoint.getSignature().getDeclaringType().getName(); Object[] args = joinPoint.getArgs(); System.out.println("该方法总会被执行"); } // 后置返回通知 @AfterReturning(value = "execution(* com.zz.proxy.after.*.*(..))",returning ="r") public void afterReturning(JoinPoint joinPoint,int r){ String name = joinPoint.getSignature().getName(); System.out.println("AAA---> The "+name+" method ends:"+r); } // 有return先执行afterReturning 在执行after // 异常就直接走 //相当于catch 只有发生异常时才会执行 @AfterThrowing(value = "execution(* com.zz.proxy.after.*.*(..))",throwing = "e") public void afterThrowing(Exception e){ // 打印异常信息 System.out.println(e.getMessage()); }
(3) 配置文件开启切面注解
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--包扫描-->
<context:component-scan base-package="com.ykq.aop.after"/>
<!--开启切面注解-->
<mvc:aspectj-autoproxy />
</beans>
(4) 测试
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
ArithmeticCalculator contextBean = (ArithmeticCalculator) context.getBean("arithmeticCalculatorImpl");
// Double add = contextBean.add(10, 2);
int add = contextBean.sub(10, 2);
System.out.println(add);
// System.out.println(10/0);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。