举例说明:小张发现妻子出轨想要离婚,于是找法院提出离婚,由于缺乏相关法律知识,法院没通过,于是小张聘请了代理人律师,由律师根据所学的法律条案向法院提出离婚,最终通过实现了离婚。在这里小张提出离婚是目标对象,律师是代理对象,律师采用的所学的法律知识就是增强额外的功能。
接下来我们用静态代理代码在实现上面的故事:
1.静态代理
//接口类(目标动作)
interface event{
public void divorce();//离婚
}
//目标实现类(实现目标动作)=>张三要求离婚
class Xiaozhang implements event{
@Override
public void divorce() {
System.out.println("老婆出轨,我要离婚");
}
}
//代理类(实现目标动作)=>代理律师用所学法律增加张三提出离婚的可行性
class Staticlawyer implements event{
private Xiaozhang xiaozhang;
public Staticlawyer(Xiaozhang xiaozhang){
this.xiaozhang=xiaozhang;
}
@Override
public void divorce() {
System.out.println("根据法律条文");
xiaozhang.divorce();
System.out.println("根据道理伦理");
}
}
public class StaticPropxy {
public static void main(String[] args) {
Staticlawyer staticlawyer=new Staticlawyer(new Xiaozhang());
staticlawyer.divorce();
}
}
输出:
总结:
静态代理模式在不改变目标对象的前提下,实现了对目标对象的功能扩展。
故事的发展:在这里我们可以看到在静态代理中,目标对象和代理对象都要实现接口类,但是问题随着来着,随着小张的离婚成功,小张一个人寂寞难耐,跑去嫖娼了,正好被警察逮到了,这时候小张又得求助他的代理律师来捞他,那么如何用代码来实现后续的故事,大家肯定想到在接口类再加个接口,我们来实现下
//接口类(目标动作)
interface event{
public void divorce();//离婚
public void crime();//犯罪
}
//目标实现类(实现目标动作)
class Xiaozhang implements event{
@Override
public void divorce() {
System.out.println("老婆出轨,我要离婚");
}
@Override
public void crime() {
System.out.println("我只是跟她一起学英语,没有嫖娼");
}
}
//代理类(实现目标动作)
class Staticlawyer implements event{
private Xiaozhang xiaozhang;
public Staticlawyer(Xiaozhang xiaozhang){
this.xiaozhang=xiaozhang;
}
@Override
public void divorce() {
System.out.println("根据法律条文");
xiaozhang.divorce();
System.out.println("根据道理伦理");
}
@Override
public void crime() {
System.out.println("根据法律条文");
xiaozhang.crime();
System.out.println("根据道理伦理");
}
}
public class StaticPropxy {
public static void main(String[] args) {
Staticlawyer staticlawyer=new Staticlawyer(new Xiaozhang());
staticlawyer.crime();
}
}
结果:
有没有发现我们的代码,在遇到这种小张这种要求多的时候,如果再继续用静态代理去处理张三的故事,就会增加代码维护成本,暴露出了缺点了
不足:静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的实现,增加维护成本
那我们就来学习我们的JDK动态代理
2.JDK动态代理
着这里我们要用到Propxy来动态生成我们的代理对象
Proxy对象的生成利用JDK的Api,在JVM内存中动态的构建Proxy对象。
在这里我们对Proxy.newProxyInstance的方法参数进行解释 @param loader 类加载器用于定义代理类 @param interfaces 接口代理类的接口列表(要实现指定的接口) @param 实现InvocationHandler的代理对象实例 @返回具有指定调用处理程序的代理实例,由指定的类加载器定义的代理类 实现指定的接口
我们先实现代理的对象:
class JdkLawyer implements InvocationHandler {
private Xiaozhang xiaozhang;
public JdkLawyer(Xiaozhang xiaozhang){
this.xiaozhang=xiaozhang;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
*
* proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
* method:我们所要调用目标对象的具体方法(这里就是通过反射获取Xiaozhang类中的method)
* args:代理对象方法传递的参数
* */
System.out.println("根据法律条文");
Object invoke=method.invoke(xiaozhang,args);//通过反射执行目标对象方法
System.out.println("根据道理伦理");
return invoke;
}
}
采用Propxy的newProxyInstance来动态生成代理对象
public class JdkPropxy {
/*
@param loader 类加载器用于定义代理类
@param interfaces 接口代理类的接口列表(要实现指定的接口)
@param 实现InvocationHandler的代理对象实例
@返回具有指定调用处理程序的代理实例,由指定的类加载器定义的代理类 实现指定的接口
*/
public static void main(String[] args) {
event e= (event) Proxy.newProxyInstance(JdkPropxy.class.getClassLoader(),new Class[]{event.class},new JdkLawyer(new Xiaozhang()));
e.crime();
}
}
总结:jdk动态代理通过Proxy的 newProxyInstance生成代理类,通过调用接口中的方法名,在代理类中调用增强后的目标方法
在这里我们可以看到动态代理是基于接口的一种代理,那么如果我们没有定义这个接口类还能不能用代理,答案是也可以,接下来介绍我们的cglib代理
3.cglib代理
这里先介绍下cglib代理的原理:
CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理,那么CGlib动态代理的精神就是继承,因为采用的是继承,所以不能对final修饰的类进行代理.如果目标方法被final修饰,那么就不能进行重写,只能继承
class Xiaozhang{
public void divorce() {
System.out.println("老婆出轨,我要离婚");
}
public final void crime() {
System.out.println("我只是跟她一起学英语,没有嫖娼");
}
}
class cglibLawer implements MethodInterceptor {
private Object target;
public Object getInstance(Object target){
//要代理的原始对象
this.target = target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
// 设置代理目标:为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而CallBack则需要实现intercept()方 法进行拦截
enhancer.setCallback(this);
return enhancer.create();
}
//实现回调方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("采取法律");
proxy.invokeSuper(obj, args);//调用业务类(父类中的方法)
System.out.println("采用道德");
return null;
}
}
运行:
public static void main(String[] args) {
// event e= (event) Proxy.newProxyInstance(JdkPropxy.class.getClassLoader(),new Class[]{event.class},new JdkLawyer(new Xiaozhang()));
// e.crime();
//cglib代理
Xiaozhang li=new Xiaozhang();
cglibLawer c=new cglibLawer();
Xiaozhang lisiproxy= (Xiaozhang) c.getInstance(li);
lisiproxy.crime();
}
到这里我们就学到了java中的三种代理的模式