您的位置:首页 > 编程语言 > Java开发

java静态代理和动态代理

2017-10-23 22:03 525 查看
按照代理的创建时期,代理类可以分为两种:

静态代理:由程序员创建代理类或特定工具自动生成源代码,再对其编译。在程序运行前代理类的.class文件就已经存在了。

动态代理:在程序运行时用反射机制动态创建。

静态代理

代理对象(Proxy)和目标对象(RealSubject)实现了相同的接口(Subject),目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。

(1)Subject接口:

public interface Subject {

public abstract void dealTask();

}


(2)RealSubject类:继承Subject接口,并实现其中的方法

public class RealSubject implements Subject {
@Override
public void dealTask() {
System.out.println("我要吃饭");
}
}


(3)代理类Proxy:继承Subject类,并把Subject作为参数通过构造参数传递。

Subject是个接口,因此在调用的时候传递的应该是他的实现类。

public class Proxy implements Subject {

// 目标对象
private Subject subject;

// 通过构造方法传入目标对象
public Proxy(Subject subject) {
this.subject = subject;
}

@Override
public void dealTask() {
System.out.println("代理来帮你做饭");

subject.dealTask();

System.out.println("代理来帮你刷碗");
}

}


(4)Client客户端调用:

public class Client {
public static void main(String[] args) {
// Proxy类中构造方法传递的是一个接口,在调用的时候就必须传递这个接口的实现类,因此是RealSubject
Subject subject = new Proxy(new RealSubject());

subject.dealTask();
}

}


控制台输出:

代理来帮你做饭
我要吃饭
代理来帮你刷碗


动态代理之JDK

为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。

代理模式:



(1)接口

public interface SubjectService {
public void getName(String name);

public void getAge(Integer age);
}


(2)实现类

public class SubjectServiceImpl implements SubjectService{
@Override
public void getName(String name) {
System.out.println("getName方法的实现类:" + name);
}

@Override
public void getAge(Integer age) {
System.out.println("getage方法的实现类"+age);
}
}


(3)代理类:继承InvocationHandler接口并重写invole方法,并把目标类作为参数传递进去

public class MyInvocationHandler implements InvocationHandler {
// 目标方法
private Object target;

public MyInvocationHandler() {
}

// 把目标方法作为参数传递
public MyInvocationHandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 是getName()方法
if ("getName".equals(method.getName())) {
System.out.println("before----" + method.getName());
Object result = method.invoke(target, args);
System.out.println("after----" + method.getName());
return result;
// 是getAge()方法
} else if ("getAge".equals(method.getName())) {
System.out.println("before----" + method.getName());
Object result = method.invoke(target, args);
System.out.println("after----" + method.getName());
return result;
} else {
Object result = method.invoke(target, args);
return result;
}
}
}


(4)客户端

public class Client {
public static void main(String[] args) {
//多态的方式
SubjectService subjectService = new SubjectServiceImpl();

//参数是接口,真正调用传递的就应该是实现类
InvocationHandler invocationHandler = new MyInvocationHandler(subjectService);

//创建代理类
SubjectService serviceproxy = (SubjectService) Proxy.newProxyInstance(
subjectService.getClass().getClassLoader(), subjectService.getClass().getInterfaces(),
invocationHandler);

serviceproxy.getName("小红");
serviceproxy.getAge(20);
}
}


控制台打印:

before----getName
getName方法的实现类:小红
after----getName
before----getAge
getage方法的实现类20
after----getAge


动态代理之CGLIB

cglib需要的jar包有asm.jar、cglib.jar

cglib,code generate library,代理类可对类进行代理,使用第三方cglib库来实现,其内部使用asm框架生成代理类的字节码,其字节码文件更加复杂,不能代理final方法,因为代理类是委托类的子类。

代理对象的生成过程由Enhancer类(CGLib的字节码增强器)实现,大概步骤如下:

1、生成代理类Class的二进制字节码;

2、通过Class.forName加载二进制字节码,生成Class对象;

3、通过反射机制获取实例构造,并初始化代理类对象。

(1)定义业务逻辑

public class Subject {
public void say(String name) {
System.out.println("hello " + name);
}
}


(2)实现MethodInterceptor接口,定义方法的拦截器

public class MyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("before----------" + method.getName() + "()");

// 调用MyInterceptor父类的方法,因为在Client类中设置了MyInterceptor的父类是Subject
Object returnObj = methodProxy.invokeSuper(object, args);

System.out.println("after----------" + method.getName() + "()");

return returnObj;
}
}


(3)使用Enhancer类生成代理类

public class Client {

public static void main(String[] args) {
// 利用Enhancer类生成代理类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Subject.class);              // 继承被代理类
enhancer.setCallback(new MyInterceptor());          // 设置回调

//采用多态的形式,因为上面通过setSuperclass设置了继承关系
Subject subject = (Subject) enhancer.create();      // 生成代理对象
subject.say("yes");
}
}


控制台输出:

before----------say
hello yes
after----------say


静态代理和动态代理的比较

静态代理的优点:

(1)代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)

静态代理的缺点:

(1)一个代理类只能代理一个业务类。如果业务类增加方法时,相应的代理类也要增加方法。。

(2)如果接口增加一个方法,除了实现类需要实现这个方法外,代理类也需要实现此方法。增加了代码维护的复杂度。

jdk和cglib动态代理实现的区别

1、jdk动态代理生成的代理类和委托类实现了相同的接口;

2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;

3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 动态代理 jdk cglib