设计模式——代理模式

目录

1:什么是代理模式

2:JDK代理模式实现

2.1:JDK静态代理

2.2:JDK动态代理

 3:动态代理缺点

4: Cglib代理方案(字节码增强)

4.1:代码实现

5:动态代理和Cblib对比 


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执行效率更高。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值