Jdk动态代理个人简单梳理
java动态代理在Spring的AOP中可谓是被应用到了极致,一直不是很清楚,今天想复习一下设计模式,刚好看到动态代理一下就把我的思绪拉回到看AOP源码的时光了,说实话动态代理我用的太少了,于是今天小总结一下,来看看。
引入如下场景:房东想租房子,但是他只想租不想管其余的琐事,于是他找中介,把房子托给他,这个中介就是一个代理者。
静态代理,十分简单:就是代理者内部聚合一个接口,这个接口是房东和中介共有的,这样就实现了静态的代理,这里就不再赘述了,代码贴出来看一眼就懂了。
// 被代理类和代理类共同的操作
interface Action {
default void doOther() {
};
void display();
}
// 被代理类【房东】
class Host implements Action {
@Override
public void display() {
System.out.println("我是房东,我只想租房子,啥也不想管");
}
}
// 代理类【中介】
class HostProxy implements Action {
private Action action;
public HostProxy() {
action = new Action() {
@Override
public void display() {
System.out.println("do nothing...");
}
};
}
public HostProxy(Action action) {
this.action = action;
}
@Override
public void display() {
PostProcessorsBeforeAction();
action.display();
PostProcessorsAfterAction();
}
private void PostProcessorsBeforeAction() {
System.out.println("我来代理你做吧");
}
private void PostProcessorsAfterAction() {
System.out.println("代理执行后序到结束");
}
}
动态代理:
// 动态代理雏形...
Action host = new Host();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理之前干事情");
host.display();
System.out.println("动态代理完成");
return null;
}
};
Action actionProxy = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class[]{Action.class}, invocationHandler);
actionProxy.display();
个人写动态代理【简单版,有时间继续探讨】:
// 自己写一下动态代理
class DynamicProxy<T> {
public T getProxy(Class<?> clazz, T obj, Object... args){
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理之前干的...事情");
// 原方法调用(这里只测试有一个方法,我取出第一个就好)
// Method[] methods = obj.getClass().getMethods();
// methods.invoke(obj, args);
method.invoke(obj, args);
System.out.println("动态代理完成啦...");
return null;
}
};
T proxyInstance = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
return proxyInstance;
}
}
// 动态代理
DynamicProxy<Action> dynamicProxy = new DynamicProxy();
Action proxy = dynamicProxy.getProxy(Action.class, new Host());
proxy.display();
动态代理稍微深入一些:
先不和Spring的Aop写的那么复杂,我先简单实现一下,其中NxjBefore就是前置方法,NxjAfter就是后置方法
// 定义这两个注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface NxjBefore {
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface NxjAfter {
}
// 接口
interface IMyReflect {
void display();
}
// 被代理类
class MyReflect implements IMyReflect{
@Override
public void display() {
System.out.println("执行方法");
}
}
class MyReflectTest{
/**
* 为了测试,包含注解有NxjBefore;NxjAfter这两个先测试
*/
@NxjBefore
public void test01() {
System.out.println("嗯哼,before啦");
}
@NxjAfter
public void test02() {
System.out.println("嗯哼,after啦");
}
}
// 自己写一下动态代理(大框和上方写的一样)
static class DynamicProxy<T> {
public T getProxy(Class<?> clazz, T obj, Object aop, Object... args){
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理之前干的...事情");
// 排好顺序
Map<Class<?>, List<Method>> chain = chain(aop.getClass().getMethods());
// 顺序调用(可以仿照Spring中AOP递归调用,这里我先简单测试一下)
List<Method> listBefore = chain.get(NxjBefore.class);
for (Method method1 : listBefore) {
method1.invoke(aop);
}
method.invoke(obj,args);
List<Method> listAfter = chain.get(NxjAfter.class);
for (Method method1 : listAfter) {
method1.invoke(aop);
}
System.out.println("动态代理完成啦...");
return null;
}
};
T proxyInstance = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
return proxyInstance;
}
}
private static Map<Class<?>, List<Method>> chain(Method[] methods) {
Map<Class<?>, List<Method>> res = new HashMap<>();
List<Method> beforeList = new ArrayList<>();
List<Method> afterList = new ArrayList<>();
for (Method method : methods) {
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
Class<? extends Annotation> aClass = annotation.annotationType();
if (aClass.equals(NxjBefore.class)) {
beforeList.add(method);
break;
} else if (aClass.equals(NxjAfter.class)) {
afterList.add(method);
}
}
}
res.put(NxjBefore.class, beforeList);
res.put(NxjAfter.class, afterList);
return res;
}
public static void main(String[] args) {
DynamicProxy<IMyReflect> dynamicProxy = new DynamicProxy();
IMyReflect proxy = dynamicProxy.getProxy(IMyReflect.class, new MyReflect(), new MyReflectTest());
proxy.display();
}
# 结果
动态代理之前干的...事情
嗯哼,before啦
执行方法
嗯哼,after啦
动态代理完成啦...
当然Spring中Aop中应用动态代理,方法执行是递归执行,大致过程为先通过方法获取链chain[此时代理对象内部方法就是按照注解标注的方式排序好的],然后递归执行方法,由后往前,当是最后一个方法是调用invoke,然后依次弹栈执行。
一篇很好的文章,值的看看:https://www.cnblogs.com/gonjan-blog/p/6685611.html