文章目录
- 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{
@Override
public void run() {
System.out.println("小汽车在路上running。。。。。。");
}
}
3.Ship.java
package com.sxs.spring.proxy;
/**
* @author 孙显圣
* @version 1.0
*/
public class Ship implements Vehicle {
@Override
public 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
*/
@Override
public 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.Test
public 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{
@Override
public double getSub(double num1, double num2) {
System.out.println("方法内部打印:" + (num1 - num2));
return num1 - num2;
}
@Override
public 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;
@Override
public 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.Test
public 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;
@Override
public 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.横切关注点-返回通知
}
}