文章目录
- 1.动态代理
- 1.需求分析
- 2.动态代理的核心
- 3.代码实例
- 1.Vehicle.java
- 2.Car.java
- 3.Ship.java
- 4.VehicleProxyProvider.java(动态代理模板)
- 5.测试使用
- 2.动态代理深入—横切关注点
- 1.需求分析
- 2.四个横切关注点
- 3.代码实例
- 1.Cal.java
- 2.CalImpl.java
- 3.VehicleProxyProvider02.java
- 4.测试
- 3.AOP问题引出
- 1.问题提出
- 2.土方法解决
- 修改VehicleProxyProvider02.java
- 3.极简AOP
- 1.SunAOP.java
- 2.修改VehicleProxyProvider02.java
1.动态代理
1.需求分析
2.动态代理的核心
动态代理主要用于对实现了接口的对象的方法调用前后进行拦截,以执行一些额外的操作,那么就要对这个接口进行动态代理
如安全检查、日志记录、事务处理等,而不需要修改原有类的代码。
3.代码实例
1.Vehicle.java
package com.sxs.spring.proxy;/*** @author 孙显圣* @version 1.0*/
public interface Vehicle {public void run();
}
2.Car.java
package com.sxs.spring.proxy;/*** @author 孙显圣* @version 1.0*/
public class Car implements Vehicle{@Overridepublic void run() {System.out.println("小汽车在路上running。。。。。。");}
}
3.Ship.java
package com.sxs.spring.proxy;/*** @author 孙显圣* @version 1.0*/
public class Ship implements Vehicle {@Overridepublic void run() {System.out.println("大轮船在路上running。。。。。。");}
}
4.VehicleProxyProvider.java(动态代理模板)
package com.sxs.spring.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author 孙显圣* @version 1.0*/
public class VehicleProxyProvider {//1.一个接口属性,需要使用构造方法传入实现接口的目标对象private Vehicle target_vehicle;public VehicleProxyProvider(Vehicle target_vehicle) {this.target_vehicle = target_vehicle;}//2.编写方法,使用Java的Proxy类动态创建并返回目标对象的代理对象public Vehicle getProxy() {//类加载器和接口信息都使用目标对象反射获取即可ClassLoader classLoader = target_vehicle.getClass().getClassLoader();Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();//4.匿名内部类实现接口,返回对象InvocationHandler invocationHandler = new InvocationHandler() {/*** 这个方法是在通过代理对象调用任何接口方法时被自动调用的。它允许在调用目标对象的方法前后执行自定义逻辑* @param proxy 代理对象* @param method 代理对象要调用的那个方法* @param args 方法的参数* @return 执行invoke方法后的结果* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//方法前的额外操作System.out.println("交通工具开始运行了。。。。。。");//调用方法Object result = method.invoke(target_vehicle, args);//方法后的额外操作System.out.println("交通工具停止运行了。。。。。。");return result;}};/*** public static Object newProxyInstance(* ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)* 这个方法有三个参数* ClassLoader loader:用于定义代理类的类加载器(一般使用目标对象的类加载器)* Class<?>[] interfaces:代理类需要实现的接口列表,这使得代理对象可以被安全地转换为这些接口中的任何一个* InvocationHandler h:InvocationHandler接口的实现类(使用匿名内部类传入)*///3.使用Proxy.newProxyInstance来返回代理对象Vehicle proxy = (Vehicle) Proxy.newProxyInstance(classLoader,interfaces, invocationHandler);return proxy;}
}
5.测试使用
package com.sxs.spring.proxy;/*** @author 孙显圣* @version 1.0*/
public class Test {@org.junit.jupiter.api.Testpublic void proxy() {Vehicle vehicle = new Ship();//创建代理类的实例,传入实现了接口的目标对象VehicleProxyProvider vehicleProxyProvider = new VehicleProxyProvider(vehicle);//获取代理对象Vehicle proxy = vehicleProxyProvider.getProxy();//使用代理对象执行方法proxy.run();}
}
2.动态代理深入—横切关注点
1.需求分析
2.四个横切关注点
- 前置通知
- 返回通知
- 异常通知
- 最终通知
3.代码实例
1.Cal.java
package com.sxs.spring.proxy;/*** 计算数量的接口** @author 孙显圣* @version 1.0*/
public interface Cal {public double getSub(double num1, double num2);public double getSum(double num1, double num2);
}
2.CalImpl.java
package com.sxs.spring.proxy;/*** @author 孙显圣* @version 1.0*/
public class CalImpl implements Cal{@Overridepublic double getSub(double num1, double num2) {System.out.println("方法内部打印:" + (num1 - num2));return num1 - num2;}@Overridepublic double getSum(double num1, double num2) {System.out.println("方法内部打印:" + (num1 + num2));return num1 + num2;}
}
3.VehicleProxyProvider02.java
package com.sxs.spring.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;/*** @author 孙显圣* @version 1.0*/
public class VehicleProxyProvider02 {//1.传入目标对象private Cal cal;public VehicleProxyProvider02(Cal cal) {this.cal = cal;}//2.编写方法获取动态代理对象public Cal getProxy() {//获取类加载器ClassLoader classLoader = cal.getClass().getClassLoader();//获取接口信息Class<?>[] interfaces = cal.getClass().getInterfaces();//4.匿名内部类实现接口返回对象InvocationHandler invocationHandler = new InvocationHandler() {Object result = null;@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {System.out.println("方法执行开始-日志-方法名-" + method.getName()+ "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知result = method.invoke(cal, args);System.out.println("方法执行正常结束-日志-方法名-" + method.getName()+ "-结果-result=" + result); //2.横切关注点-返回通知} catch (Exception e) {System.out.println("方法出现异常-日志-方法名-" + method.getName()+ "-异常类型=" + e.getClass().getName()); //3.横切关注点-异常通知} finally {System.out.println("方法最终结束-日志-方法名-" +method.getName()); //4.横切关注点-最终通知return result; //返回方法的执行结果}}};//3.返回动态代理对象Cal proxy = (Cal) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);return proxy; //返回动态代理对象}
}
4.测试
@org.junit.jupiter.api.Testpublic void VehicleProxyProvider02Test() {CalImpl cal = new CalImpl();VehicleProxyProvider02 vehicleProxyProvider02 = new VehicleProxyProvider02(cal);Cal proxy = vehicleProxyProvider02.getProxy();proxy.getSub(3,1);System.out.println("===========================================");proxy.getSum(2,4);}
3.AOP问题引出
1.问题提出
2.土方法解决
修改VehicleProxyProvider02.java
package com.sxs.spring.proxy03;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;/*** @author 孙显圣* @version 1.0*/
public class VehicleProxyProvider02 {//1.传入目标对象private Cal cal;public VehicleProxyProvider02(Cal cal) {this.cal = cal;}public void before(Method method, Object[] args) {System.out.println("方法执行开始-日志-方法名-" + method.getName()+ "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知}public void after(Method method, Object result) {System.out.println("方法执行正常结束-日志-方法名-" + method.getName()+ "-结果-result=" + result); //2.横切关注点-返回通知}//2.编写方法获取动态代理对象public Cal getProxy() {//获取类加载器ClassLoader classLoader = cal.getClass().getClassLoader();//获取接口信息Class<?>[] interfaces = cal.getClass().getInterfaces();//4.匿名内部类实现接口返回对象InvocationHandler invocationHandler = new InvocationHandler() {Object result = null;@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {before(method, args);result = method.invoke(cal, args);after(method, result);} catch (Exception e) {System.out.println("方法出现异常-日志-方法名-" + method.getName()+ "-异常类型=" + e.getClass().getName()); //3.横切关注点-异常通知} finally {System.out.println("方法最终结束-日志-方法名-" +method.getName()); //4.横切关注点-最终通知return result; //返回方法的执行结果}}};//3.返回动态代理对象Cal proxy = (Cal) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);return proxy; //返回动态代理对象}
}
3.极简AOP
1.SunAOP.java
package com.sxs.spring.proxy03;import java.lang.reflect.Method;
import java.util.Arrays;/*** @author 孙显圣* @version 1.0*/
public class SunAOP {public static void before(Method method, Object[] args) {System.out.println("方法执行开始-日志-方法名-" + method.getName()+ "-参数" + Arrays.asList(args)); //1.横切关注点-前置通知}public static void after(Method method, Object result) {System.out.println("方法执行正常结束-日志-方法名-" + method.getName()+ "-结果-result=" + result); //2.横切关注点-返回通知}
}