Java代理入门
代理概念
通过上图相信可以很直观的了解到代理的作用:可以有效的实现调用方和被调用方的解耦以及对调用方的检查,一些。这样双方之间就无需了解更多细节,而是通过代理对象来中转。
Java静态代理
静态代理是指代理对象持有目标对象的句柄(指针或引用),可以在代理对象中增添一些新的方法从而可以起到一些额外作用,实现对方法的增强。
下面通过一个例子来进行具体说明:
package proxy.静态代理;
/**
* @author pony
* @date 2020/5/1
* 这是一个被调用方的接口,使用此接口的好处是可以给被定义的被调用方定规范,当 被调用方发生变换时,还可以很好的实现切换
*/
public interface Subject {
public void request();
}
package proxy.静态代理;
/**
* @author pony
* @date 2020/5/1
* 对接口的实现,该类就是一个被调用方
*/
public class SubjectImpl implements Subject {
@Override
public void request() {
System.out.println("dealinng the quest");
}
}
package proxy.静态代理;
/**
* @author pony
* @date 2020/5/1
* 代理类,由于要代理Subject故要实现其接口
*/
public class StaticProxy implements Subject{
//实际对象,这就是前面所说的代理对象持有目标对象(被调用方)的句柄
private Subject sub;
public StaticProxy(Subject sub) {
this.sub = sub;
}
//这是核心内容,通过重载此方法达到方法增强的目的
@Override
public void request() {
System.out.println("preprocess");
sub.request();
System.out.println("postprocess");
}
}
package proxy.静态代理;
/**
* @author pony
* @date 2020/5/1
* Demo类
*/
public class StaticProxyDemo {
public static void main(String[] args) {
//创建真实目标对象
SubjectImpl sub = new SubjectImpl();
//创建代理对象
StaticProxy staticProxy1 = new StaticProxy(sub);
staticProxy1.request();
}
}
通过以上代码可以很容易理解静态代理的实现原理,这也是其优点所在,但每当接口中多一个方法时,就需要在代理类和目标类中都重载次方法,而且在代理类中还要调用被调用类的方法。实在是有些繁琐。而动态代理却可以有效的避免这个问题
动态代理
上图是动态代理的原理图:可以看到,当通过代理对象(由Java帮我们生成)调用目标对象的方法时,会统一进入到代理处理器里面去,代理处理器就是一个实现了InvocHandler接口的类,主要方法是invoke方法,当调用目标对象的任一方法时,都会进入到invoke方法。在invoke方法里面就可以实现对原有方法的动态增强。下面看一个例子:
package proxy.动态代理;
/**
* @author pony
* @date 2020/5/1
* 目标类的接口
*/
public interface Subject {
public void request();
}
package proxy.动态代理;
/**
* @author pony
* @date 2020/5/1
* 目标类的实现
*/
public class SubjectImpl implements Subject {
@Override
public void request() {
System.out.println("deal request");
}
}
package proxy.动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author pony
* @date 2020/5/1
* 代理处理器,实现了InvocationHandler接口
*/
public class ProxyHandler implements InvocationHandler {
private Subject sub; //代理处理器中包含目标对象的句柄
public ProxyHandler(Subject sub) {
this.sub = sub;
}
/**
* 代理对象在调用任何方法时都会进入到该函数
* @param o:代理类,这里由Java帮我们生成
* @param method:被调用的方法名
* @param objects:方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println(o.getClass().getName());
System.out.println("preprocess"); //这里将是动态代理的精髓之处,在不修改源码的情况下实现方法增强、终于get到这个点了
Object rs = method.invoke(sub, objects); //反射的用法
System.out.println("postprocess");
return rs;
}
}
package proxy.动态代理;
import java.lang.reflect.Proxy;
/**
* @author pony
* @date 2020/5/1
* Demo类
*/
public class DynamicProxyDemo {
public static void main(String[] args) {
//创建目标对象
SubjectImpl sub = new SubjectImpl();
//创建ProxyHandler对象
ProxyHandler handler = new ProxyHandler(sub);
//动态创建代理对象,不修改源码的基础上对方法增强
Subject proxySub = (Subject) Proxy.newProxyInstance(SubjectImpl.class.getClassLoader(), SubjectImpl.class.getInterfaces(), handler);
//request方法会自动调用handler的invoke方法
proxySub.request();
System.out.println(proxySub.getClass().getName()); //该输出表明目标对象是Proxy类帮我们生成的
}
}
运行结果如下:
在动态代理中要注意当代理类实现多个接口时如果里面由同名方法,默认使用第一个符合的方法。
AOP编程
AOP(Aspect Object Programing)也即面向切面编程,我的理解是对于某些任一模块都需要的一些东西不是通过类的继承来实现,而是通过横切面的方式来定义。AOP是一种思想,其本质还是java的动态代理技术,在真正调用某一个方法的时候在其前和其后增添一些诸如事务控制,日志之类的东西就可以很好做到横向切分。从而在更加细粒度的层面上(方法)实现了解耦,提高了代码的复用性。