一、代理
public interface Calculator {//加int add(int a, int b);//减int sub(int a, int b);//乘int mul(int a, int b);//除int div(int a, int b);
}
1.1 静态代理
public class CalculatorImpl implements Calculator {@Overridepublic int add(int a, int b) {int res = a+b;System.out.println("方法内部 result = " + res);return res;}@Overridepublic int sub(int a, int b) {int res = a-b;System.out.println("方法内部 result = " + res);return res;}@Overridepublic int mul(int a, int b) {int res = a*b;System.out.println("方法内部 result = " + res);return res;}@Overridepublic int div(int a, int b) {int res = a/b;System.out.println("方法内部 result = " + res);return res;}
}
public class CalProxy implements Calculator {//把被代理目标对象传递进来private Calculator calculator;public CalProxy(Calculator calculator) {this.calculator = calculator;}@Overridepublic int add(int a, int b) {System.out.println("[日志] add 方法开始了,参数是:"+a+","+b);int result = calculator.add(a,b);System.out.println("[日志] add 方法结束了,返回值是:"+result);return result;}@Overridepublic int sub(int a, int b) {System.out.println("[日志] sub 方法开始了,参数是:"+a+","+b);int result = calculator.sub(a,b);System.out.println("[日志] sub 方法结束了,返回值是:"+result);return result;}@Overridepublic int mul(int a, int b) {System.out.println("[日志] mul 方法开始了,参数是:"+a+","+b);int result = calculator.mul(a,b);System.out.println("[日志] mul 方法结束了,返回值是:"+result);return result;}@Overridepublic int div(int a, int b) {System.out.println("[日志] div 方法开始了,参数是:"+a+","+b);int result = calculator.div(a,b);System.out.println("[日志] div 方法结束了,返回值是:"+result);return result;}
}
1.2 动态代理
/*动态代理*/
public class ProxyFactory {//目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}//返回代理对象public Object getProxy(){/** 三个参数* 1.classLoader加载动态生成代理类的类加载器* 2.interface目标对象实现的所有接口的class类型数组* 3.handler设置代理对象实现目标对象方法的过程* */ClassLoader classLoader = target.getClass().getClassLoader();Class<?>[] interfaces = target.getClass().getInterfaces();InvocationHandler handler = 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 res = method.invoke(target, args);//调用方法后日志的输出System.out.println("[动态代理][日志]:" + method.getName() + ",结果:" + res);return res;}};return Proxy.newProxyInstance(classLoader, interfaces, handler);}
}
测试
@Testpublic void test(){//1.创建动态代理对象ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());Calculator proxy = (Calculator) proxyFactory.getProxy();proxy.add(3,5);}
二、AOP
通过预编译方式和运行期动态代理方式实现,在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。
jdk动态代理和cglib动态代理:
有接口使用jdk代理,生成接口实现类代理对象--代理对象和目标对象实现同样的接口
没有接口使用cglib代理,生成子类代理对象---通过继承被代理的目标类
2.1 添加依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.2</version></dependency>
2.2 Calculate接口和实现类
public interface Calculator {//加int add(int a, int b);//减int sub(int a, int b);//乘int mul(int a, int b);//除int div(int a, int b);
}
public class CalculatorImpl implements Calculator {@Overridepublic int add(int a, int b) {int res = a+b;System.out.println("方法内部 result = " + res);return res;}@Overridepublic int sub(int a, int b) {int res = a-b;System.out.println("方法内部 result = " + res);return res;}@Overridepublic int mul(int a, int b) {int res = a*b;System.out.println("方法内部 result = " + res);return res;}@Overridepublic int div(int a, int b) {int res = a/b;System.out.println("方法内部 result = " + res);return res;}
}
2.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:aop="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.hait"/><!--开启Aspectj自动代理,为目标对象生成代理--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
切面类
@Aspect //切面类
@Component //ioC容器
public class LogAspect {//设置切入点和通知类型//1.通知类型:// 前置@Before(value="execution(权限修饰符 方法返回值 增强方法的全类名.方法名(参数类型))")//* com.hait.dao.impl.CalculatorImpl.*(..)表示包中的所有类的所有方法任意参数类型@Before(value = "execution(* com.hait.dao.impl.*.*(..))")public void beforeMethod(JoinPoint joinPoint){String method = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("Logger-->前置通知,方法名:"+method+"参数:"+ Arrays.toString(args));}// 返回@AfterReturning()@AfterReturning(value = "execution(* com.hait.dao.impl.*.*(..))",returning = "res")public void afterReturning(JoinPoint joinPoint,Object res){String method = joinPoint.getSignature().getName();System.out.println("Logger-->返回通知,方法名:"+method+",返回值:"+res);}// 异常@AfterThrowing()---目标方法出现异常时执行@AfterThrowing(value = "execution(* com.hait.dao.impl.*.*(..))",throwing = "ex")public void afterThrowing(JoinPoint joinPoint,Exception ex){String method = joinPoint.getSignature().getName();System.out.println("Logger-->异常通知,方法名:"+method+",异常:"+ex);}// 后置@After()@After(value = "execution(* com.hait.dao.impl.*.*(..))")public void afterMethod(JoinPoint joinPoint){String method = joinPoint.getSignature().getName();System.out.println("Logger-->后置通知,方法名:"+method);}// 环绕@Around()@Around(value = "execution(* com.hait.dao.impl.*.*(..))")public Object aroundMethod(ProceedingJoinPoint joinPoint){String method = joinPoint.getSignature().getName();String args = joinPoint.getArgs().toString();System.out.println("Logger-->环绕通知,方法名:"+method);Object res = null;try {System.out.println("Logger-->环绕通知----目标方法之前执行");//调用目标方法res = joinPoint.proceed();System.out.println("Logger-->环绕通知----目标方法之后执行");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("Logger-->环绕通知----目标方法出现异常执行");}finally {System.out.println("Logger-->环绕通知----目标方法执行完毕执行");}return res;}}
测试
@Testpublic void test02() {ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");Calculator calculator = ac.getBean(Calculator.class);calculator.div(3, 0);}
没有异常的话
三、重用切入点表达式
//重用切入点表达式@Pointcut(value = "execution(* com.hait.dao.impl.*.*(..))")public void pointCut(){}// 后置@After()/*如果pointCut方法不在本类中,那么value的值是方法的全路径*@After(value = "com.hait.annoaop.LogAspect.pointCut()")*/@After(value = "pointCut()")public void afterMethod(JoinPoint joinPoint){String method = joinPoint.getSignature().getName();System.out.println("Logger-->后置通知,方法名:"+method);}