目录
1:什么是代理模式
代理模式是23中设计模式中的一种,我们在应用中访问B对象,B对象有增删改查方法,我们想要在B对象的某一个方法前置后置执行一些我们需要的操作,方法1可以直接在b方法中直接添加代码,但是当我们需要在很多的对象类似B对象的某一个方法之前之后执行某一些操作,我们要更改的类就会很多,代码修改跟麻烦。所有就有了代理模式。我们指定一个A对象持有B对象,并且A对象具有B对象。我们通过访问代理对象,从而实现增强。从外部统一访问代理对象。
组成:
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
2:JDK代理模式实现
无论是静态代理和动态代理,都是基于接口和实现类的。
通用的接口和实现类代码如下
//接口的增删改查方法
public interface Dao {
public void add();
public void select();
}
//委托类实现接口
//独有方法动态代理不能增强
public class DaoImpl implements Dao{
public void add() {
System.out.println("委托类的add方法");
}
public void select() {
System.out.println("委托类的select方法");
}
//独有方法,动态代理不能增强
public void run1111() {
System.out.println("委托类的run1111方法----");
}
}
2.1:JDK静态代理
静态代理:静态代理扩展性差,需要手写代码,调用代理类,代理类然后调用委托类实现增强。
//静态代理也要实现接口,提供和委托类一样的方法
//静态代理类不利扩展,需要手写代码
public class JingProxy implements Dao{
//创建实现类对象,便于调用实现类方法
Dao dao=new DaoImpl();
//调用委托类方法,对add方法实现增强
public void add() {
// TODO Auto-generated method stub
System.out.println("----------静态代理方法执行之前----------");
dao.add();
System.out.println("----------静态代理方法执行之后----------");
}
//没有增强,直接调用委托类
public void select() {
dao.select();
}
public static void main(String[] args) {
JingProxy proxy=new JingProxy();
proxy.add();
}
}
2.2:JDK动态代理
动态代理:
1:有虚拟机在运行的时候动态的创建对象,虚拟机来卸载 和清除,生产的代理类加载到方法区
2:相比于静态代理不需要实现接口,定义一个一个相同的方法
3:通过 Proxy.newProxyInstance 创建的代理对象是在JVM运行的时候生成的对象,他不是InvocationHandler类型的,也不是我们定义的接口类型,而是咋jvm运行的时候,动态的生产的一个对象,命名是 $+proxy+数字($Proxy0 )
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理实现InvocationHandler,代理类必须实现接口
public class DongProxy implements InvocationHandler{
private Object object;
public DongProxy(Object object) {
super();
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强add方法,或者是所有包含add的方法均可
if("add".equals(method.getName())) {
System.out.println("-----动态代理方法之前增强------");
Object o=method.invoke(object, args);
System.out.println("-----动态代理方法之后增强------");
return o;
}
return method.invoke(object, args);
}
//自定义通用方法创建代理对象
public Object createProxy() {
Object proxy=Proxy.newProxyInstance(
object.getClass().getClassLoader(), //类加载器
object.getClass().getInterfaces(), //接口
this);//InvocationHandler自定义处理类
return proxy;
}
public static void main(String[] args) {
//Spring的ioc实现了对bean的管理
//配置文件又可以指定方法,所以动态代理可以通过配置文件实现。灵活性很高
//委托类(Spring实现bean管理)
Dao dao=new DaoImpl();
//代理类强转为 委托类
Dao daoProxy=(Dao) new DongProxy(dao).createProxy();
daoProxy.add();
daoProxy.select();
}
}
通过调用Proxy静态方法Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器
注意Proxy.newProxyInstance()方法接受三个参数:
ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
3:动态代理缺点
缺点1:必须是实现接口
缺点2:实现类中独有的方法在生成的代理类中不能调用,也就是不能增强。
4: Cglib代理方案(字节码增强)
Cglib特点:
1:由于没有继承接口的类,无法使用JDK的动态代理,所有此缺陷引入新的技术Cglib。CGLIB使用的是底层字节码技术,可以为一个类创建一个子类,从而解决无接口代理的问题。
2:在内存中创建一个子类对象,继承被代理类
3:目标类方法能是flnal类型
4.1:代码实现
目标类代码:
//Cglib不需要实现接口
public class Dao {
public void add() {
System.out.println("Cglib代理运行add方法");
};
public void select() {
System.out.println("Cglib代理运行select方法");
};
//final修饰方法不能使用Cglib
public final void select11() {
System.out.println("Cglib代理运行select方法");
};
}
Cglib代理类代码:
//实现MethodInterceptor(方法拦截器接口) method interceptor
public class CglibProxy implements MethodInterceptor{
Object object;
public CglibProxy(Object object) {
super();
this.object = object;
}
//外部方法,创建代理类
public Object createCglibProxy() {
//1:创建核心类
Enhancer enhancer=new Enhancer();
//2:设置父类
enhancer.setSuperclass(object.getClass());
//3:设置回调
enhancer.setCallback(this);
//4:返回代理类
Object o=enhancer.create();
return o;
}
//方法拦截器实现方法
public Object intercept(Object proxy, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
Object oo = null;
//配置文件读取指定增强方法
if("add".equals(arg1.getName())) {
System.out.println("---方法之前增强---");
oo=arg3.invokeSuper(proxy, arg2);
System.out.println("---方法之后增强---");
return oo;
}
return arg3.invokeSuper(proxy, arg2);
}
public static void main(String[] args) {
Dao dao=new Dao();
CglibProxy cglibProxy=new CglibProxy(dao);
Dao proxy=(Dao) cglibProxy.createCglibProxy();
proxy.add();
proxy.select();
}
}
输出结果:
5:动态代理和Cblib对比
1.JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
2.JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
3.JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。