Java代理模式
静态代理
代理类自己编写,在编译器已经确认了代理类。
实现步骤
1.定义接口及其实现类
public interface SayHelloService {void say();
}
public class SayHelloServiceImpl implements SayHelloService {
@Override
public void say() {
System.out.println("Hello Bitch");
}
}
2.定义类代理对象
public class SayHelloServiceProxy implements SayHelloService {private SayHelloService target;
public SayHelloServiceProxy(SayHelloService service) {
this.target = service;
}
@Override
public void say() {
System.out.println("记录日志。。。。。。");
target.say();
System.out.println("清理数据。。。。。。");
}
public static void main(String[] args) {
SayHelloServiceProxy proxy = new SayHelloServiceProxy(new SayHelloServiceImpl());
proxy.say();
}
}
代理类实现了目标对象的接口,对原有得接口做了扩展,其中所有的对象都是在编译期都确定好了。
缺点
需要代理对象实现目标对象的接口,假如目标对象方法很多或者需要代理多个对象,复杂度就会很高。
而动态代理不需要在编译期确定代理类,可以在运行时期动态生成,反射是动态代理的一种实现方式。
java中的动态代理
主要由以下两种方式实现:
JDK动态代理
JDK动态代理需要目标对象实现一个或多个接口,否则只能使用CGLIB实现动态代理。
实现步骤
1.定义目标类和公共接口
public interface UserService {void add();
}
public class UserServiceImpl implements UserService {
@Override
public void add() {
// TOD Auto-generated method stub
System.out.println("-------add--------");
}
}
2.定义调用处理器类,可以再运行时生成代理类,并带上一些增强的功能
java.lang.reflect.Proxy : 这是生成代理类的主类,通过 Proxy 类生成的代理类都继承了 Proxy 类,即 DynamicProxyClas extends Proxy。
java.lang.reflect.InvocationHandler:调用处理类
public class MyInvocationHandler implements InvocationHandler {private Object target;
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------begin " + method.getName() + "------");
Object result = method.invoke(target, args);
System.out.println("------end " + method.getName() + "-------");
return result;
}
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
}
public static void main(String[] args) {
UserService service = new UserServiceImpl();
MyInvocationHandler handler = new MyInvocationHandler(service);
UserService proxy = (UserService) handler.getProxy();
proxy.add();
}
}
原理解析
上面关键点在于Proxy.newProxyInstance() 方法创建了一个代理对象,查看他的源码,封装了创建代理类及对象的方法,如下:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
其中的getProxyClass0(loader, intfs)实际生成了代理类,这个代理类是动态代理的关键,因为是在运行时动态生成的,我们可以通过下面的方法将生成的文件显示出来,探探究竟
public static void main(String[] args) throws IOException {byte[] testProxies = ProxyGenerator.generateProxyClass("Proxy0", UserServiceImpl.class.getInterfaces());
String path = "E:/userProxies.class";
FileOutputStream fileOutputStream = new FileOutputStream(path);
fileOutputStream.write(testProxies);
fileOutputStream.flush();
fileOutputStream.close();
}
反编译生成的文件如下
public final class Proxy0 extends Proxy implements UserService {private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void add() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("org.example.proxy.inter.UserService").getMethod("add");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
分析:jdk动态生成了一个代理类,继承于Proxy,当我们调用add()方法时,将此方法当做参数传了进去,super.h.invoke(this, m3, (Object[])null)。 最终调用了InvocationHandler的invoke方法。
InvocationHandler的invoke:
public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
通过反射,得到被代理对象的方法实现。
一整套下来,达到了代理的功能。
Cglib动态代理
Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 Java 类与实现 Java接口。
public class CglibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
//实现 MethodInterceptor接口方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("前置代理");
//通过代理类调用父类中的方法
Object result = methodProxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过生成子类的方式创建代理类
UserServiceImpl proxyImp = (UserServiceImpl) proxy.getProxy(UserServiceImpl.class);
proxyImp.add();
}
}
二者区别
使用动态代理的对象必须实现一个或多个接口
使用 cglib 代理的对象则无需实现接口,达到代理类无侵入。
SpringAOP
主要由JDK动态代理和CGLIB动态代理实现
JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类。如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。
CGLIB(Code Genration Libray),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。
以上是 Java代理模式 的全部内容, 来源链接: utcz.com/z/391702.html