AOP前景提要
提出问题
①代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
②代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。
动态代理
- 代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
- 代理的方式
- 基于接口的动态代理:JDK动态代理
Proxy:所有动态代理类的父类,专门用户生成代理类或者代理对象
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
用于生成代理类的Class对象.
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
用于生成代理对象
InvocationHandler :完成动态代理的整个过程.
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
附上代码:
public interface ArithmeticCalculator {
public int add(int i,int j);
public int sub(int i,int j);
public int mul(int i,int j);
public int div(int i,int j);
}
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j ;
return result ;
}
@Override
public int sub(int i, int j) {
int result = i - j ;
return result ;
}
@Override
public int mul(int i, int j) {
int result = i * j ;
return result ;
}
@Override
public int div(int i, int j) {
int result = i / j ;
return result ;
}
}
创建InvocationHandler类,实现InvocationHandler接口,这个类中持有一个被代理对象的实例target。InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。再在invoke方法中执行被代理对象target的相应方法。当然,在代理过程中,我们在真正执行被代理对象的方法前加入自己其他处理。这也是Spring中的AOP实现的主要原理,这里还涉及到很重要的关于java反射方面的基础知识。
public class ArithmeticCalculatorProxy {
//目标对象
private ArithmeticCalculator target ;
public ArithmeticCalculatorProxy(ArithmeticCalculator target) {
this.target = target ;
}
//获取代理对象的方法
public Object getProxy() {
//代理对象
Object proxy ;
/**
* loader: ClassLoader对象。 类加载器对象. 帮我们加载动态生成的代理类。
*
* interfaces: 接口们. 提供目标对象的所有的接口. 目的是让代理对象保证与目标对象都有接口中想同的方法.
*
* h: InvocationHandler类型的对象.
*/
ClassLoader loader = target.getClass().getClassLoader();
Class [] interfaces = target.getClass().getInterfaces();
//执行newProxyInstance不会调用invoke
proxy = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
/**
* invoke: 代理对象调用代理方法, 会回来调用invoke方法。
*
* proxy: 代理对象 , 在invoke方法中一般不会使用.
*
* method: 正在被调用的方法对象.
*
* args: 正在被调用的方法的参数.
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//将方法的调用转回到目标对象上.
//获取方法的名字
String methodName = method.getName();
//记录日志
System.out.println("LoggingProxy==> The method " + methodName+" begin with "+ Arrays.asList(args));
Object result = method.invoke(target, args); // 目标对象执行目标方法. 相当于执行ArithmeticCalculatorImpl中的+ - * /
//记录日志
System.out.println("LoggingProxy==> The method " + methodName +" ends with :" +result );
return result ;
}
});
return proxy ;
}
}
JDK动态代理的另外一种方式
public class ArithmeticCalculatorProxy2 {
//动态代理: 目标对象 如何获取代理对象 代理要做什么
//目标对象
private ArithmeticCalculator target ;
public ArithmeticCalculatorProxy2(ArithmeticCalculator target) {
this.target = target ;
}
//获取代理对象的方法
public Object getProxy() throws Exception {
//代理对象
Object proxy ;
ClassLoader loader = target.getClass().getClassLoader();
Class [] interfaces = target.getClass().getInterfaces();
Class proxyClass = Proxy.getProxyClass(loader, interfaces);
//Class 创建对象? newInstance()
Constructor con =
proxyClass.getDeclaredConstructor(InvocationHandler.class);
proxy = con.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//将方法的调用转回到目标对象上.
//获取方法的名字
String methodName = method.getName();
//记录日志
System.out.println("LoggingProxy2==> The method " + methodName+" begin with "+ Arrays.asList(args));
Object result = method.invoke(target, args); // 目标对象执行目标方法. 相当于执行ArithmeticCalculatorImpl中的+ - * /
//记录日志
System.out.println("LoggingProxy2==> The method " + methodName +" ends with :" +result );
return result ;
}
});
return proxy ;
}
}
创建代理对象并进行测试
public static void main(String[] args) {
//将动态生成的proxy保存下来
Properties properties = System.getProperties();
properties.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//目标对象
ArithmeticCalculator target =new ArithmeticCalculatorimpl();
//获取代理对象
Object obj=new Proxy(target).getProxy();
ArithmeticCalculator arithmeticCalculator=(ArithmeticCalculator)obj;
System.out.println(arithmeticCalculator.getClass().getName());
System.out.println(arithmeticCalculator.add(1,2));
}
测试结果如下
生成的Proxy
package com.atguigu.spring.aop.proxy;
import com.atguigu.spring.aop.proxy.ArithmeticCalculator;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy00 extends Proxy implements ArithmeticCalculator {
private static Method m1;
private static Method m2;
private static Method m4;
private static Method m3;
private static Method m6;
private static Method m5;
private static Method m0;
public $Proxy00(InvocationHandler arg0) throws {
super(arg0);
}
public final boolean equals(Object arg0) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{arg0})).booleanValue();
//这里又返回了InvocationHandler中的invoke方法
} catch (RuntimeException | Error arg2) {
throw arg2;
} catch (Throwable arg3) {
throw new UndeclaredThrowableException(arg3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error arg1) {
throw arg1;
} catch (Throwable arg2) {
throw new UndeclaredThrowableException(arg2);
}
}
public final int mul(int arg0, int arg1) throws {
try {
return ((Integer)super.h.invoke(this, m4, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
} catch (RuntimeException | Error arg3) {
throw arg3;
} catch (Throwable arg4) {
throw new UndeclaredThrowableException(arg4);
}
}
public final int add(int arg0, int arg1) throws {
try {
return ((Integer)super.h.invoke(this, m3, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
} catch (RuntimeException | Error arg3) {
throw arg3;
} catch (Throwable arg4) {
throw new UndeclaredThrowableException(arg4);
}
}
public final int sub(int arg0, int arg1) throws {
try {
return ((Integer)super.h.invoke(this, m6, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
} catch (RuntimeException | Error arg3) {
throw arg3;
} catch (Throwable arg4) {
throw new UndeclaredThrowableException(arg4);
}
}
public final int div(int arg0, int arg1) throws {
try {
return ((Integer)super.h.invoke(this, m5, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
} catch (RuntimeException | Error arg3) {
throw arg3;
} catch (Throwable arg4) {
throw new UndeclaredThrowableException(arg4);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error arg1) {
throw arg1;
} catch (Throwable arg2) {
throw new UndeclaredThrowableException(arg2);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("mul",
new Class[]{Integer.TYPE, Integer.TYPE});
m3 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("add",
new Class[]{Integer.TYPE, Integer.TYPE});
m6 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("sub",
new Class[]{Integer.TYPE, Integer.TYPE});
m5 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("div",
new Class[]{Integer.TYPE, Integer.TYPE});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException arg1) {
throw new NoSuchMethodError(arg1.getMessage());
} catch (ClassNotFoundException arg2) {
throw new NoClassDefFoundError(arg2.getMessage());
}
}
}
结束语
代理对象能否转换成目标对象的类型?
代理对象调用代理方法,为什么会执行 InvocationHandler中的invoke 方法?
转载:https://blog.csdn.net/qq_39728274/article/details/105074343
查看评论