文章目录
- AOP(面向切面)
- 一、代理
- 静态代理
- 代码实现
- 1、创建一个接口和一个实现类(目标类)
- 2、创建代理类实现接口,在创建一个此接口的属性,且创建有参构造
- 3、创建测试类进行测试
- 动态代理
- 代码实现
- 使用Pxoy类去实现动态代理,输出日志
- 测试动态代理的效果
- 二、基于的注解AOP实现日志
- 代码实现加解析
- 前置准备、导入依赖
- 一、创建一个接口和实现类代表目标类,可以直接使用上面CalculatorImpl类,在实现类类中标记@Component注解
- 二、创建bean.xml
- 三、创建切面类完成日志
- 测试
AOP(面向切面)
概念:切面就是将代码逻辑做横向切面,相同逻辑的部分分装到一个进行统一管理
作用:1、提高代码的复用性 2、增强代码的维护性
一、代理
概念: 在讲到面向切面之前必不可少的就是需要知道什么是代理,代理就是继承一个目标类的代理类,在代理类来完成一些比较繁琐的代码如:输出日志等,当需要使用到核心代码时再去调用目标类的方法,这样子目标类就会变得更加的简洁明了。
简单的来说就是:一个明星(目标类)他只需要负责唱歌、跳舞等核心的事情,而明星的经济人(代理类)就需要告诉明星他需要到哪里进行演出、到哪里进行演讲等这些琐事
静态代理
逻辑:创建一个接口和实现类(目标类),在创建一个代理类也实现此接口,这时代理类就有了目标类的所有方法,此时就可以实现某一个方法在代理类中的方法进行输出日志、调用目标类的方法等操作,测试时就可以直接进行调用代理类即可。
代码实现
这里就拿一个简单的计算机的逻辑来讲解
1、创建一个接口和一个实现类(目标类)
2、创建代理类实现接口,在创建一个此接口的属性,且创建有参构造
3、创建测试类进行测试
此时就相当于完成了近似于代理的操作
动态代理
概念:动态代理就是将目标类中的所有方法都进行统一处理,实现方法就是去使用Poxy类中的方法
代码实现
这里创建目标类这一步就直接调用上面静态代理中的即可
使用Pxoy类去实现动态代理,输出日志
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;public class dynamicsProxy{// 目标对象(需要被代理的对象)private Object object;public dynamicsProxy(Object object) {this.object = object;}// 返回代理对象public Object getProxy(){
// 加载动态生成代理类的加载器ClassLoader classLoader = object.getClass().getClassLoader();
// 获取对象的所有接口Class<?>[] interfaces = object.getClass().getInterfaces();
// 设置代理目标对象的过程InvocationHandler invocationHandler = new InvocationHandler() {//proxy:需要被代理的对象//method:需要被重写的类//args[]:重写方法中的形参@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws Throwable {// 执行核心代码前的日志System.out.println("[动态代理][日志],方法名为:"+method.getName()+"方法的参数"+ Arrays.toString(args));Object result = method.invoke(object, args);// 执行核心代码后的日志System.out.println("[动态代理][日志]结束了,运行结果为:"+result);return result;}};return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);}
}
测试动态代理的效果
二、基于的注解AOP实现日志
概念:注解AOP相对于上面动态和静态代理实现日志便捷了许多,且还添加了许多的功能
代码实现加解析
前置准备、导入依赖
<!-- spring Aop依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.2</version></dependency><!-- spring Aspects依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.2</version></dependency><!-- sprint context依赖--><!-- 当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.2</version></dependency>
一、创建一个接口和实现类代表目标类,可以直接使用上面CalculatorImpl类,在实现类类中标记@Component注解
二、创建bean.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"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.spring`在这里插入代码片`framework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
<!--基于AOP的实现:1、将目标对象和切面交给IOC容器(注解+扫描)2、开启AspectJ的自动自动代理,为目标对象自动生成代理3、将切面类通过注解@Aspect表示
-->
<!-- 将目标对象和切面交给IOC容器(注解+扫描)--><context:component-scan base-package="org.example.annoAop"></context:component-scan>
<!-- 开启AspectJ的自动自动代理,为目标对象自动生成代理--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
三、创建切面类完成日志
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.util.Arrays;@Aspect//切面类
@Component//ioc容器
public class LogAspect {
// 设置切面点和通知的类型
// 通知类型:
// 切入点表达式:execution【固定格式】(public int【权限修饰符,方法返回值(可以写*表示两值任意都可以)】
// org.example.annoAop【方法所在类的全类名(这里写*表是包名任意,写*..表示报名任意同时报的层次深度任意)】.CalculatorImpl
// add【方法名】(int,int)【形参列表,..表示任意】
// )
// 前置通知 @Before(切入点表达式)@Before("execution(public int org.example.annoAop.CalculatorImpl.*(..))")public void beforeMethod(JoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();System.out.println("前置通知,方法名为:"+methodName);}
// 后置通知 @After(切入点表达式)@After("execution(* org.example.annoAop.CalculatorImpl.*(..))")public void afterMethod(JoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("后置通知,方法名为:"+methodName+"形参列表为:"+ Arrays.toString(args));}
// 返回通知 @AfterReturning@AfterReturning(value = "execution(public int org.example.annoAop.CalculatorImpl.*(..))",returning = "obj")public void afterReturning(JoinPoint joinPoint,Object obj){String methodName = joinPoint.getSignature().getName();System.out.println("返回通知,方法名为:"+methodName+"返回结果:"+obj);}
// 异常通知 @AfterThrowing@AfterThrowing(value = "execution(public int org.example.annoAop.CalculatorImpl.*(..))",throwing = "e")public void afterThrowing(JoinPoint joinPoint,Throwable e){String methodName = joinPoint.getSignature().getName();System.out.println("异常通知,方法名为:"+methodName+"报错信息:" + e);}
// 环绕通知 @Around()
// 概念:环绕通知可以使用try..catch..finally完成以上四种通知@Around(value = "pointcut()")public Object around(ProceedingJoinPoint pJoinPoint){String name = pJoinPoint.getSignature().getName();Object[] args = pJoinPoint.getArgs();Object result = null;try {System.out.println("环绕通知:前置效果,方法名为:" + name);//执行内部方法result = pJoinPoint.proceed();System.out.println("环绕通知:返回效果,方法名为:" + name + "返回结果:" + result);}catch (Throwable e) {e.printStackTrace();System.out.println("环绕通知:异常效果,方法名为:"+ name +"报错信息:" + e);} finally{System.out.println("环绕通知:后置效果,方法名为:" + name + "形参列表:" + Arrays.toString(args));}return result;}// 重用切入点表达式@Pointcut("execution(public int org.example.annoAop.CalculatorImpl.*(..))")public void pointcut(){}
}
测试
详细内容