目录
一、jdk的动态代理如何使用
1. 需要动态代理的接口
package com.yihua.base.proxy.jdk.v1;
/**
* 用户服务
*
* @author YiHua
* @date 2022/4/12 14:38
*/
public interface UserService {
/**
* 新增用户
*
* @param username
* @param password
*/
void addUser(String username, String password);
}
2. 需要代理的实际对象
package com.yihua.base.proxy.jdk.v1;
/**
* 用户服务
*
* @author YiHua
* @date 2022/4/12 14:39
*/
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username, String password) {
System.out.println("传入参数为 username: " + username + " password: " + password);
}
}
3. 实现处理器接口
package com.yihua.base.proxy.jdk.v1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理类
* jdk的动态代理:定义一个实现 InvocationHandler 接口的代理类,重写 invoke () 方法,且添加 getProxy () 方法。
*
* @author YiHua
* @date 2022/4/12 14:41
*/
public class JdkProxy implements InvocationHandler {
// 定义被代理的类,也就是需要代理的目标对象
private Object targetObject;
/**
* 无参构造
*/
public JdkProxy() {
}
/**
* 定义获取代理对象方法
*
* @param targetObject 需要代理的对象
* @return 代理对象
*/
public Object getProxyObject(Object targetObject) {
// 给被代理的对象服务
this.targetObject = targetObject;
// 获取到被代理对象的实例
Class<?> c = targetObject.getClass();
// 通过反射获取,被代理对象的:类加载器、这个类实现的接口
ClassLoader classLoader = c.getClassLoader();
Class<?>[] interfaces = c.getInterfaces();
// 通过反射类提供的newProxyInstance方法,创建提供的代理类实例
return Proxy.newProxyInstance(classLoader, interfaces, this);
}
/**
* 处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法
*
* @param proxy 调用该方法的代理实例
* @param method Method实例对应于代理实例上调用的接口方法
* @param args 一个对象数组,其中包含在代理实例上的方法调用中传递的参数值,如果接口方法不接受任何参数,则null
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态代理,监听开始!");
System.out.println("动态代理增强原来的方法>>>>>>>>>>>>>>>>>>>>>>");
String username = (String) args[0];
String password = (String) args[1];
// 增强信息:只能添加指定用户"admin、123"
System.out.println("开始权限校验");
if (!(username.equals("admin") && password.equals("123"))) {
System.out.println("新增用户信息不合法");
return null;
}
System.out.println("权限校验成功,可以新增");
System.out.println("动态代理增强结束<<<<<<<<<<<<<<<<<<<<<<<<");
// 这个是真正的执行方法,这个method是反射获取的,直接使用它的invoke方法执行
Object result = method.invoke(targetObject, args);
System.out.println("JDK动态代理,监听结束!");
return result;
}
}
4. 测试类
package com.yihua.base.proxy.jdk.v1;
/**
* 测试基于实现类的方式
*
* @author YiHua
* @date 2022/4/12 14:38
*/
public class JdkProxyByClassTest {
public static void main(String[] args) {
// 实例化JDKProxy对象
JdkProxy jdkProxy = new JdkProxy();
// 目标对象(被代理的对象)
UserServiceImpl userServiceImpl = new UserServiceImpl();
// 获取到代理对象
UserService userService = (UserService) jdkProxy.getProxyObject(userServiceImpl);
// fixme 这里代理类无法强转为被代理对象的实现类,否则会转换失败,这里也印证jdk的代理只能代理实现了接口的对象
// UserServiceImpl userService = (UserServiceImpl) jdkProxy.getProxyObject(userServiceImpl);
// 执行新增方法
userService.addUser("admin", "123");
}
}
二、实现简单的aop
(1)基于接口的实现
1. 需要动态代理的接口
package com.yihua.base.proxy.jdk.v2;
/**
* 订单服务
*
* @author YiHua
* @date 2021/12/7 11:33 上午
*/
public interface OrderService {
/**
* 支付
*/
void pay() throws InterruptedException;
/**
* 展示
*/
void show();
}
2. 需要代理的实际对象
package com.yihua.base.proxy.jdk.v2;
/**
* 订单服务
*
* @author YiHua
* @date 2021/12/7 11:33 上午
*/
public class OrderServiceImpl implements OrderService {
int status = 0;
/**
* 下单
*/
@Override
public void pay() throws InterruptedException {
Thread.sleep(50);
this.status = 1;
System.out.println("pay success, pay status " + this.status);
}
/**
* 展示
*/
@Override
public void show() {
int a = 1 + 2;
System.out.println("order status " + this.status);
}
}
3. 动态代理接口
package com.yihua.base.proxy.jdk.v2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
/**
* 动态代理接口
*
* @author YiHua
* @date 2021/12/8 12:24 上午
*/
public interface Aspect {
/**
* 在...之前
*/
void before();
/**
* 在...之后
*/
void after();
/**
* 创建一个代理
*
* @param tClass 需要代理的对象
* @param aspects 实现这个接口的对象的项目路径
* @param <T>
*/
static <T> T createProxy(Class<T> tClass, String... aspects) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 存储所有实现了该接口的,的实例对象
ArrayList<Aspect> list = new ArrayList<>();
// 遍历传递进来的路径,通过反射获取实例对象
for (String aspect : aspects) {
Class<?> aClass = Class.forName(aspect);
Aspect asp = (Aspect) aClass.getConstructor().newInstance();
list.add(asp);
}
// 获取到被代理对象的实例
T instance = tClass.getConstructor().newInstance();
ClassLoader classLoader = tClass.getClassLoader();
Class<?>[] interfaces = tClass.getInterfaces();
// 生成一个代理对象
return (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
for (Aspect aspect : list) {
aspect.before();
}
Object invoke = method.invoke(instance,args);
for (Aspect aspect : list) {
aspect.after();
}
return invoke;
}
});
}
}
4. 测试类
package com.yihua.base.proxy.jdk.v2;
import java.lang.reflect.InvocationTargetException;
/**
* 测试基于接口的实现方式
*
* @author YiHua
* @date 2021/12/8 1:00 上午
*/
public class JdkProxyByInterfaceTest {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, InterruptedException {
// 区别于通过实现类的实现方式,通过接口的静态方法直接获取代理对象
OrderService orderService = Aspect.createProxy(OrderServiceImpl.class, "com.yihua.springboot.aop.proxy.jdk.interf.InterfaceTimeAspect");
orderService.pay();
orderService.show();
}
}
(2)基于注解的实现
1. 需要动态代理的接口
package com.yihua.base.proxy.jdk.v2;
/**
* 订单服务
*
* @author YiHua
* @date 2021/12/7 11:33 上午
*/
public interface OrderService {
/**
* 支付
*/
void pay() throws InterruptedException;
/**
* 展示
*/
void show();
}
2. 需要代理的实际对象(注意这里使用的自定义的注解)
package com.yihua.base.proxy.jdk.v2;
/**
* 订单服务
*
* @author YiHua
* @date 2021/12/7 11:33 上午
*/
@Aspect(type = InterfaceTimeAspect.class)
public class OrderServiceImpl implements OrderService {
int status = 0;
/**
* 下单
*/
@Override
public void pay() throws InterruptedException {
Thread.sleep(50);
this.status = 1;
System.out.println("pay success, pay status " + this.status);
}
/**
* 展示
*/
@Override
public void show() {
int a = 1 + 2;
System.out.println("order status " + this.status);
}
}
3. 定义增强的接口
/**
* 定义增强的相关方法的接口
*
* @author YiHua
* @date 2021/12/8 11:41 上午
*/
public interface IAspect {
void before();
void after();
}
4. 定义实现类,具体的增强逻辑
package com.yihua.base.proxy.jdk.v3;
import com.yihua.base.proxy.jdk.v2.Aspect;
/**
* 实现增强的相关方,定义具体地增强逻辑
*
* @author YiHua
* @date 2021/12/8 12:31 上午
*/
public class InterfaceTimeAspect implements IAspect {
long start;
@Override
public void before() {
this.start = System.currentTimeMillis();
}
@Override
public void after() {
long resTime = System.currentTimeMillis() - this.start;
System.out.format("time resTime: %dms\n", resTime);
}
}
5. 切面注解
package com.yihua.base.proxy.jdk.v3;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 切面注解
*
* @author YiHua
* @date 2021/12/8 11:38 上午
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
Class<?> type();
}
6. 定义代理工厂
package com.yihua.base.proxy.jdk.v3;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedList;
/**
* 代理工厂
*
* @author YiHua
* @date 2021/12/8 11:45 上午
*/
public class ObjectFactory {
public static <T> T newInstance(Class<T> tClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 获取传入的类所有的注解,例如传入了'orderServiceImpl'
Annotation[] annotations = tClass.getAnnotations();
// 定义一个list装载这些'切面'
LinkedList<IAspect> iAspects = new LinkedList<>();
// 遍历所有的注解,找出'Aspect'注解,这个类似于'切点'
// 将这个引用的类创建实例,然后保存起来,后续会通过这些实例去执行,切面中的方法
for (Annotation annotation : annotations) {
if (annotation instanceof Aspect) {
Class<?> type = ((Aspect) annotation).type();
IAspect iAspect = (IAspect) (type.getConstructor().newInstance());
iAspects.push(iAspect);
}
}
// 这个实例就是用来执行真正的主方法,使用传入的类创建实例,相当于 new ,例如 OrderServiceImpl o = new OrderServiceImpl;
T instance = tClass.getConstructor().newInstance();
ClassLoader classLoader = tClass.getClassLoader();
Class<?>[] interfaces = tClass.getInterfaces();
// 返回jdk的动态代理对象,切面方法会在本类中执行,实际业务会在外面显示调用,在内部通过反射的方式调用
return (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
iAspects.forEach(IAspect::after);
Object invoke = method.invoke(instance, args);
iAspects.forEach(IAspect::before);
return invoke;
}
});
}
}