利用java反射机制实现动态代理

目录

一、引言

二、静态代理

三、动态代理

总结:


一、引言

        谈及动态代理,我们首先要了解一个概念:什么是代理?

        举一个例子,假如你要选购房屋,一般情况下你联系的肯定是房屋中介,通过房屋中介来看房子,你不可能直接去找房地产开发商联系,而此时的房屋中介充当的就是代理的角色。

        那么我们再来回顾一下设计模式中的代理模式:

        代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。

        代理模式角色分为 3 种:
        Subject(抽象主题角色):定义代理类和真实主题的公共对外方法,通常被设计成接口;
        RealSubject(真实主题角色):真正实现业务逻辑的类;
        Proxy代理主题角色):用来代理和封装真实主题;

        代理模式的核心是代理角色

二、静态代理

        所谓静态代理,简单来说,在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。

        代码实现:

        Subject 抽象主题角色:

public interface Subject {//抽象主题,规范了其子类的操作
	//对外暴露的统一行为方法
	public void request();
}

        RealSubject真实主题角色:

public class RealSubject implements Subject{//真实主题

	@Override
	public void request() {
		System.out.println("1.");
		System.out.println("2.");
		System.out.println("3.");
	}

}

        SubjectProxy 代理角色:

public class SubjectProxy implements Subject{
	private Subject target;//真实主题角色
	
	public SubjectProxy() {
		target=new RealSubject();//创建真实主题角色
	}
	@Override
	public void request() {
		System.out.println("---begin---");//实现的额外功能
		target.request();//真实主题的功能
		System.out.println("----end---");
		
		
	}
	

}

        测试类:

//代理
public class ProxyDemo {
	public static void main(String[] args) {
		//创建代理主题
		//接口的引用 ==> 代理对象
		Subject sub=new SubjectProxy();
		sub.request();
		
	}

}

       在我们这个例子上,可以看出,是将代理主题类SubjectProxy在编译期就写好了,即将代理类写死。

        为什么说是将代理类写死呢?是因为你创建的这个代理角色的,它的具体实现是根据当前的真实主题和抽象主题创建的,换一个别的真实主题和抽象主题就不适用了。

        我们怎么解决这一问题的?这就要利用动态代理来实现了。

三、动态代理

        动态代理是指在程序运行期间由JVM根据反射等机制动态的生成代理类。

        代码实现:

        UserService抽象主题角色

public interface UserService {//抽象主题角色
	void select();
	void update();
}

        UserServiceImpl真实主题角色

// 真正的实现类
public class UserServiceImpl implements UserService {

	@Override
	public void select() {
		System.out.println("select * ..................");
		System.out.println("数据库中完成用户信息的查询执行!");
	}

	@Override
	public void update() {
		System.out.println("update ...................");
		System.out.println("数据库中用户状态的更新执行!");
	}

}

       LogInvacationHandler日志处理器对象类()

public class LogInvacationHandler implements InvocationHandler {
	//创建目标对象
	
	private Object target;
	public  LogInvacationHandler(Object obj) {
		this.target=obj;
	}

	//拦截器
	//该方法作用,根据传入的代理对象(proxy)以及调用的方法(method)来决定具体的调用
	//invoke()方法在创建具体的代理类是被调用
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.printf("方法%s开始加载,Time:%s\n",method.getName(),new Date());
		
		//执行目标对象target的方法
		//根据你传入的具体实现类target及参数args调用具体的方法
		Object o=method.invoke(target, args);
		Thread.sleep(1000);
		System.out.printf("方法%s开结束加载,Time:%s\n",method.getName(),new Date());
		return o;
	}

}

        测试类:

public class DynamicUserServiceProxyDemo {
	public static void main(String[] args) {
		
		//创建动态处理器
		//根据你传入的具体实现类不同,实现不同的方法调用
		LogInvacationHandler handler=new LogInvacationHandler(new UserServiceImpl());
		
		//创建动态代理对象
		//根据该接口的类加载器、该接口以及动态处理器创建具体的代理角色
		
        UserService proxy=(UserService)Proxy.newProxyInstance(
				UserService.class.getClassLoader(), //该接口的类加载器
				new Class[] {UserService.class},//该接口
				handler//动态处理器
				);
		//代理对象调用对应的方法时,被动态处理器invoke方法拦截
		//invoke方法根据创建的代理对象以及调用的方法来决定具体调用哪个方法
		proxy.select();//调用对应的method方法
		
		
	}

}

        实现结果:

        创建的LogInvacationHandler类的invoke()方法实现了将具体实现类的方法和增添的部分结合起来,根据具体传入的目标对象的不同来达到不同的实现。

        在具体的测试类中,创建的具体的LogInvacationHandler类,但invoke()方法并没有被直接调用,但它仍然起到了连接具体实现类和增添的新功能的作用,这是为什么呢?

        先观察一下invoke()方法:

        

        可以结合LogInvacationHandler的代码以及其本身方法头看出,invoke()方法在这里充当拦截器的作用,创建了具体的日志处理对象handler后,在具体的根据Proxy的newProxyInstance()方法传入公共的类加载器、具体实现类的实现接口(或接口数组)以及处理器创建具体代理对象时,invoke()被隐式的调用了。

        创建好proxy这个对象后,

        

        此时,将方法名 "select" 以及具体的代理类 "proxy" 传入invoke()方法,此时方法的参数为0,所以invoke()方法的args是一个空数组。然后结合具体实现类的 select () 方法包装成一个具有更多功能的类并输出。

        为什么说动态代理利用了反射机制呢?就是因为,两个关键字:“运行时”和“动态”。运行时才能具体的确定业务需求,实现的功能,然后动态的去生成代理类,在实现对具体业务需求的包装,最后输出,这就离不开反射。

        可以说,没有反射机制,动态代理类就无法生成。

总结:

        1.动态代理实现了更好的代码复用。

        2.java反射机制(运行时+动态)是动态代理的关键。

        3.充分理解invoke()方法的实现机制和作用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值