静态代理和动态代理
动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。可以给这个类创建一个代理,故名思议就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强。
动态代理实现:首先必须定义一个接口,还要有一个InvocationHandler(将实现接口的类的对象传递给它)处理类。再有一个工具类Proxy(习惯性将其称为代理类,因为调用他的newInstance()可以产生代理对象,其实他只是一个产生代理对象的工具类)。利用到InvocationHandler,拼接代理类源码,将其编译生成代理类的二进制码,利用加载器加载,并将其实例化产生代理对象,最后返回。
静态代理:
优点:
1、 实现松散耦合。
2、做到在不修改目标对象的功能前提下,对目标功能扩展。
缺点:
如果项目中有多个类,则需要编写多个代理类,工作量大,不好修改,不好维护,不能应对变化。
一、静态代理
创建接口
public interface Examable {
void exam();
}
创建学生类实现接口
public class Student implements Examable {
@Override
public void exam() {
System.out.println("超级无敌棒棒糖!");
}
}
创建代理对象
public class Cheater implements Examable {
//被代理对象
private final Examable student;
public Cheater(Examable student){
this.student=student;
}
@Override
public void exam() {
System.out.println("现场漂移");
student.exam();//调用Student类的方法
}
}
测试
public class MainTest {
//组合优于继承
public static void main(String[] args) {
//cheater 就是一个代理对象
//因为它是受student 委托,完成某个功能
//它要完成的主要功能,来自student
//除了委托做的事情,可能还会扩展一些行为
Examable ex = new Student();//原来的行为
ex .exam();
System.out.println("------下面是代理行为------");
Examable cheater = new Cheater(xiaoming);
cheater.exam();
}
}
二、动态代理
1.动态代理,使用cglib实现
在maven仓库找到cglib依赖
创建类
public class Student {
public void exam(){
System.out.println("超级无敌棒棒糖!");
}
}
创建CglibProxy类实现接口
package com.nf147.sim.proxy.p5;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
/*
* 参数
* Object 为由CGLib动态生成的代理类实例
* method 为上文中实体类所调用的被代理的方法引用
* objects 为参数值列表
* methodProxy 为生成的代理类对方法的代理引用
* return 从代理实例的方法调用返回的值
* */
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o, objects);
}
}
测试
package com.nf147.sim.proxy.p5;
import com.nf147.sim.proxy.p1.Student;
import net.sf.cglib.proxy.Enhancer;
public class Main {
public static void main(String[] args) {
//第一种方式
//增强器,动态代码生成器
Enhancer enhancer = new Enhancer();
//设置 生成类 的 父类
enhancer.setSuperclass(Student.class);
//回调函数
enhancer.setCallback(new CglibProxy());
//动态生成字节码并返回代理对象
Student o = (Student) enhancer.create();
o.exam();
System.out.println("-----------");
//第二种方式
//这里是简化写法
//第一个参数 设置 生成类 的父类 ,第二参数 被代理类的所有接口 ,回调函数
Student student = (Student) Enhancer.create(Student.class, null, new CglibProxy());
student.exam();
}
}
2.动态代理,使用JDK内置的Proxy实现
创建接口
public interface Examable {
void exam();
}
创建一个类,实现接口
public class Student implements Examable {
@Override
public void exam() {
System.out.println("超级无敌棒棒糖!");
}
}
创建JdkProxy类,实现 InvocationHandler 接口
public class JdkProxy implements InvocationHandler {
private Object object;//被代理
public JdkProxy() {
}
public JdkProxy(Object object) {
this.object = object; 初始化的时候就赋值
}
/**
* 当用户调用对象中的每个方法时都通过下面的方法执行,方法必须在接口
* proxy 被代理后的对象
* method 将要被执行的方法信息(反射)
* args 执行方法时需要的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
Object invoke = null;
try {
invoke = method.invoke(object, args);
} catch (Exception e) {
System.out.println("异常的信息" + e.getMessage());
}
return invoke;//调用被代理对象原来的方法(行为)
}
}
测试
public class MainTest {
public static void main(String[] args) {
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数person1.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
ClassLoader cl= Thread.currentThread().getContextClassLoader();
Examable o = (Examable) Proxy.newProxyInstance(
cl,//类加载器
new Class[]{Examable.class},//获取被代理对象的所有接口
new JdkProxy(new Student())//InvocationHandler对象
);
o.exam();//代理后的行为
}
}