Java代理机制

Java代理模式,就是通过代理对象来访问目标对象,扩展目标对象的功能,比如:当你的项目以及写完了,但是突然要求新增一个功能,在每个业务操作前去判断权限,如果直接修改源代码的话,就会很麻烦,甚至破坏业务结构,这时候使用代理来扩展功能就很合适。
静态代理
静态代理就是写一个接口或者父类,让代理对象和目标对象都实现这个接口或者继承这个父类,然后调用相同的方法,这里其实就是对Java多态思想的应用。

//公用的接口
public interface StaticBiz {
	public void say();
}

//真实的业务方法去实现业务接口
public class StaticBizImpl implements StaticBiz{

	@Override
	public void say() {
		System.out.println("这是原生的say方法");
	}
	
}
//代理对象也实现业务接口,同时保存需要代理的对象
public class StaticBizImplProxy implements StaticBiz{
	//保存需要代理的对象(父类的引用指向子类对象)
	private StaticBiz statizBiz;
	
	public StaticBizImplProxy(StaticBiz statizBiz) {
		this.statizBiz = statizBiz;
	}

	@Override
	public void say() {
		//调用需要扩展的方法,追加日志或者管理权限等等
		System.out.println("这是我的扩展");
		//调用正在的业务方法
		this.statizBiz.say();
	}
	
}
//测试类
public class StaticProxyTest {
	public static void main(String[] args) {
		StaticBiz staticBiz = new StaticBizImpl();
		
		StaticBizImplProxy proxy = new StaticBizImplProxy(staticBiz);
		proxy.say();
	}
}	

在这里插入图片描述
这里有一个有意思的问题,就是我的代理类StaticBizImplProxy就算不实现StaticBiz接口,也可以实现一样的功能,为什么还要实现这个接口呢?
这里其实就是在真实的开发中,我们使用的是面向接口的开发方式,也就是说,在实际的开发中,我们的代码是这样的:

StaticBiz staticBiz = new StaticBizImpl();
//调用业务方法
staticBiz.say();

当我们使用代理时,代码是这个的:

StaticBiz staticBiz = new StaticBizImplProxy();
//调用代理对象的方法,增加功能
staticBiz.say();

我们发现这样的话,我们的代理对象可以直接替换目标对象,在项目中直接使用,但是如果代理对象不实现StaticBiz 接口,则不能使用这种方法,那我们就还是要修改源代码,没有真正起到代理对象的作用。
静态代理模式的优点:实现很简单,也不需要知道目标对象的实际功能,只需要专注于我们要扩展的功能。
缺点:
1、每个代理对象都需要实现接口,那如果接口发生改变,不仅仅要改变目标对象的方法,还要修改代理对象的方法,使得维护变得麻烦。
2、一个代理对象只能对应一种类型的目标对象,如果项目中目标对象有很多种,那么就得有很多种代理对象,比如当例子中除了StaticBiz,还有StaticBiz2、StaticBiz3…StaticBizN的话,我们就得写N种代理对象。

动态代理
在上面的例子中,我们针对个业务实现类都要创建一个代理类来扩充,主要是因为在静态代理中,代理对象是在编译期就已经写好了,不能做很好的扩展,我们就想,能不能有一种办法,使得我们在运行期根据不同的实现类来自动的产生对应的代理类呢?这就是动态代理。
动态代理,也就是在运行期间,jvm根据我们需要添加代理的类动态生成代理类,有如下特点:
1、目标类必须实现接口
2、代理类不需要实现目标类的接口,但必须实现InvocationHandler接口

//业务方法的接口
public interface UserBiz {
	public void say(String name,String age);
}
//业务方法的实现类
public class UserBizImpl implements UserBiz{

	@Override
	public void say(String name, String age) {
		System.out.println("我叫:"+name+",今年:"+age+"岁");
	}
	
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理的代理类需要实现InvocationHandler 接口
public class Handler implements InvocationHandler {
	//与静态代理类似,动态代理也需要保存代理对象,但是因为编译时不知道代理对象的类型,所以用object
	private Object targetObject;
	//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
	public Object newProxyInstance(Object targetObject) {
		this.targetObject=targetObject;
		//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例    
        //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器  
        //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口  
        //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法  
        //根据传入的目标返回一个代理对象  
		return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
	}

	@Override
	//proxy表示代理,method表示原对象被调用的方法,args表示方法的参数
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//这是自己添加的扩展方法
		System.out.println("需要扩展的方法");
		//调用原始的业务方法,是用java反射实现
		Object ret=method.invoke(targetObject, args);
		return ret;
	}
	
}

//测试
public class HandlerProxyTest {
	public static void main(String[] args) {
		Handler handler = new Handler();
		UserBiz user = (UserBiz) handler.newProxyInstance(new UserBizImpl());
		user.say("张三", "22");
	}
}

在这里插入图片描述
Cglib代理
我们是用静态代理或者动态代理时发现,我们都需要使目标对象继承类或者实现接口,但是如果我们的目标对象没有实现任何接口或者继承任何类,那我们该怎么办?
这时候我们可以是用Cglib代理,Cglib底层是构建一个目标类的子类来实现扩展,所以这就表示我们的目标类不能是final(不能被继承)的,并且需要扩展的方法不能是final或者static修饰(不能被执行代理)
Cglib不是JDK提供的代理方法,所以使用前需要导入依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.5</version>
</dependency>
//业务类
public class UserService {
	public void say() {
		System.out.println("这是业务方法");
	}
}
//代理类必须实现MethodInterceptor
public class Cglib implements MethodInterceptor {
	//需要保存的目标对象
	private Object target;
	
	//给目标对象创建一个代理对象
    public Object getProxyInstance(Object target) {
    	this.target=target;
        //工具类
        Enhancer en = new Enhancer();
        //设置父类
        en.setSuperclass(this.target.getClass());
        //设置回调函数
        en.setCallback(this);
        //创建子类代理对象
        return en.create();
    }
	
	@Override
	public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		//你需要扩展的方法
		System.out.println("这是扩展方法");
		//调用真实的业务方法
		Object obj = method.invoke(target);
		return obj;
	}
	
}
//测试
public class CglibTest {
	public static void main(String[] args) {
		Cglib cglib = new Cglib();
		UserService user = (UserService) cglib.getProxyInstance(new UserService());
		user.say();
	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值