动态代理模式(实例化详解)

110 篇文章 0 订阅
95 篇文章 0 订阅

简介

代理模式通常用于达到对原有系统功能进行扩充的目的,

比如:你刚接手一个别人没有完成的项目,这时你不想动别人原来的代码,还需要添加新功能。这时代理模式,这时代理模式会很好的帮我们解决问题
代理模式一般分为静态代理,动态代理两种
静态代理

静态代理一般是由一个接口、若干实现类、若干代理类构成

静态代理模式,代理类聚合了被代理类,且代理类及被代理类都实现了同一个接口,可实现灵活多变。继承式的实现方式则不够灵活。
缺点就是如果在追加两个功能那么还需要在创建两个代理类,这样就会导致代理类越来越多,管理越来越困难。这是动态代理就运用而生了

学习动态代理,不可避免的要用到下面一个接口和一个类。

  1. InvocationHandler接口
  2. Proxy类

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理。在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样对每一个方法或方法组合进行处理

public class ListDemo {
 @SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String[] args) {
	final List list = new ArrayList<>();
	Object oo = Proxy.newProxyInstance(
//			原始数据类型
			List.class.getClassLoader(),
//			定义接口
			list.getClass().getInterfaces(),
//			调用处理
			new InvocationHandler() {
				
				@Override
				public Object invoke(
//						代理对象
						Object proxy,
//						代理方法
						Method method, 
//						代理参数
						Object[] args) throws Throwable {
					// TODO Auto-generated method stub
					System.out.println("加入几个对象:");
					Object returnValue = method.invoke(list, args);
					System.out.println("加入完成");
					if (method.getName().equals("size")) {
						return 100;
					}
					return returnValue;
				}
			});
	List list2 = (List)oo;
	list2.add("123");
	list2.add("456");
	System.out.println("size:"+list2.size()+","+list.size());
}
}

程序启动时,每当我们对list2进行操作时,都会进入到oo这个代理里面,到下面的new InvocationHandler接口下面的invoke方法里面,进行我们的业务逻辑处理,1.第一次进入是在我们第一次list2.add("123");2.第二次进入是在list2.add("456");,3.第三次进入是在list2.size(),所以“加入几个对象”“加入完成”总共打印了三次。为什么list.size是2呢?以为我们在Proxy.newProxyInstance下,定义的原始数据类型是List,定义的接口时list.getClass,所以Proxy.newProxyInstance他的上一级是List,最后我们调用list.size时候,此时list数组长度就是2,所以打印出来的结果就是2

package com.xdszj.proxy.service;

/**
 * @author Administrator
 *这个接口中的业务就是返回衣服的价格
 */
public interface IBoss {
	int ifu(String size);
}
package com.xdszj.proxy.service.impl;

import com.xdszj.proxy.service.IBoss;

/**
 * @author Administrator
 *实现了买衣服的接口
 *自己定义的业务,买裤子
 */
public class Boss implements IBoss{

	@Override
	public int ifu(String size) {
		// TODO Auto-generated method stub
		System.out.println("天猫小强旗舰店,老板给客户发快递----衣服型号为:"+size);
//		这件衣服的价格是送数据库读取的
		return 50;
	}
	public void kuzi() {
		System.out.println("天猫小强旗舰店,老板给客户发快递----裤子");
	}
}

 

 老板去买衣服时候,此时就不需要代理工作了,所以一切按部就班

package com.xdszj.proxy.action;

import org.junit.jupiter.api.Test;

import com.xdszj.proxy.service.IBoss;
import com.xdszj.proxy.service.impl.Boss;

/**
 * @author Administrator
 *不使用代理,直接调用方法
 *方法中规定什么业务,
 *就只能调用什么业务,
 *回到什么返回值,
 *就只能输出什么返回值
 */
public class SaleAction {

	@Test
	public void saleByBossSelf() {
		IBoss boss = new Boss();
		System.out.println("老板亲自上阵");
		int money = boss.ifu("XL");
		System.out.println("衣服成交:"+money);
	}
}

 不行老板说,我太累了,我要找个代理去为我干活,此时代理就孕育而生

package com.xdszj.proxy.proxyClass;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Administrator
 *
 */
public class ProxyBoss {

	@SuppressWarnings("unchecked")
	public static <T>T getProxy(
			final int discountCoupon,
			final Class<?> interfaceClass,
			final Class<?> implementsClass) {
		
		return (T) Proxy.newProxyInstance(
				interfaceClass.getClassLoader(), 
				new Class[] {interfaceClass},
				new InvocationHandler() {
					
					@Override
					public Object invoke(
							Object proxy,
							Method method,
							Object[] args) throws Throwable {
						// TODO Auto-generated method stub
						Integer invoke = (Integer) method.invoke(implementsClass.newInstance(),
								args);
						return invoke - discountCoupon;
					}
				});
	}
}

代理出现以后,所有的一切业务逻辑全部在new InvocationHandler(){}方法进行,代理只需要知道他要取做事情的那个接口类,和实现类就可以了,不必知道里面到底有什么,在这里我们的原始数据类型和定义接口全部写成动态的,不要写死。

package com.xdszj.proxy.action;

import org.junit.jupiter.api.Test;

import com.xdszj.proxy.proxyClass.ProxyBoss;
import com.xdszj.proxy.service.IBoss;
import com.xdszj.proxy.service.impl.Boss;

/**
 * @author Administrator
 *什么是动态代理?
 *简单的写一个模板接口,剩下的个性化工作,
 *好给动态代理来完成
 */
public class ProxySaleAction {

	/**
	 * 使用代理,在这个代理中,只代理了Boss的衣服方法
	 * 定制化业务,可以改变原接口的参数,返回值等
	 */
	@Test
	public void saleByProxy() {
		IBoss boss = ProxyBoss.getProxy(10,
				IBoss.class,
				Boss.class);
		System.out.println("代理经营");
		int money = boss.ifu("XL");
		System.out.println("衣服成交价:"+money);
	}
}

 

代理可以对其原接口中的参数,返回值做改变。整个过程我们并没有改变原始接口,实现类的代码,实现了不同的效果,代理模式,个人觉得就像是切面编程,在不改变原有代码的基础上添加新的功能。要想让代理功能增加,此时我们只需要在接口中定义方法,让实现类进行实现即可,代理变扩展了新的功能,动态代理模式,功能易于修改,个性化的工作,有代理全权负责

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值