代理模式

介绍: 在不修改现有的功能到的代码的基础上,实现现有功能的增强(不修改核心功能的代码,但实现核心功能的增强),符合程序的开闭原则;原来功能进行了封装后不动,可以完成功能的升级

静态代理模式

实现了可以不对原来代理对象进行修改,且实现原有功能的增强
程序的开发阶段:分开实现,原有的核心功能和需要增强的功能分开实现
程序的运行阶段:需要将分开的功能进行整合
静态代理的构成:

代理接口
目标类(target)
代理类(proxy)拥有目标类对象的引用
客户端(client)需要使用代理类的对象,具备原来的核心功能和增强功能
注: 代理类和目标类,实现同一个接口

案例

代理接口:

public interface UserService {	
	/**
	 * 实现用户身份的验证
	 */
	Boolean checkUsers(String uname,String upwd);

}

目标类:

public class UserServiceImpl implements UserService {

	/**
	 * 核心功能
	 * 实现用户的效验
	 */
	@Override
	public Boolean checkUsers(String uname, String upwd) {
		// TODO Auto-generated method stub
		System.out.println("=====用户的身份验证  核心功能======");
		if("admin".equals(uname) && "1234".equals(upwd)) {
			return true;
		}
		return false;
	}

代理类:

public class UserServiceImpl2 implements UserService {

	/**
	 * 增强功能
	 * 
	 * 实现用户登录的时候进行日志记录
	 */
	@Override
	public Boolean checkUsers(String uname, String upwd) {
		// TODO Auto-generated method stub
		
		//声明UserService变量
		UserService userService = new UserServiceImpl();
		
		System.out.println(uname + "==在这个时间" + new Date() + " == 尝试登录系统");
	
		return userService.checkUsers(uname, upwd);
	}

}

客户端:

public class StaticTest {

	public static void main(String[] args) {
		//创建对象
		UserService userService2 = new UserServiceImpl2();
		
		userService2.checkUsers("admin", "1234");
	}
}

静态代理的不足:

如果接口发生变化,需要维护两个实现类,维护目标类和代理类;
需要为每一个目标类,都创建一个代理类对象,导致程序的臃肿

动态代理模式

**解决问题:**频繁的创建代理类,JDK在内存中直接产生一个class文件,通过该class文件创建代理类对象,接口发生变化,需要修改代理类,在内存中产生class文件,是在程序运行的时候,代理类实现的接口对象class文件已经加载到了内存,产生的代理类class文件中已经重写了相应的方法。

动态代理实现的相关API

Proxy:创建动态代理和代理类的实例化

public static Object newProxyInstance(ClassLoader loader,<?>[] interfaces,
                                      InvocationHandler h)
                               throws IllegalArgumentException
返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
Proxy.newProxyInstance因为与IllegalArgumentException相同的原因而Proxy.getProxyClass 。

参数
loader - 类加载器来定义代理类
interfaces - 代理类实现的接口列表
h - 调度方法调用的调用处理函数。

InvocationHandler :需要改接口实现类对象传入newProxyInstance方法

Object invoke(Object proxy,
              方法 method,
              Object[] args)
       throws Throwable
处理代理实例上的方法调用并返回结果。 当在与之关联的代理实例上调用方法时,将在调用处理程序中调用此方法。
参数
proxy - 调用该方法的代理实例
method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。

ClassLoader:类加载器,将编译好的class文件拷贝到内存中,是有ClassLoader实现的,我们自定义的接口,类对应的ClassLoader都是一样的

案例:

通过动态代理实现权限的控制:模拟对数据库的CRUD操作,查询不需要进行控制(查询不需要修改数据库数据),如果进行crud方法的调用,调用者如果拥有权限,直接进行数据库的操作,否则提示权限不足
PetDao 接口

public interface PetDao {

	/**
	 * 实现对宠物的crud
	 * 其中 对添加  修改  删除  进行登录控制的权限效验
	 * 只有查询不进行效验
	 */
	int add();
	
	int update();
	
	int delete();
	
	List<?> select();	
}

核心功能类:

public class PetDaoImpl implements PetDao {

	@Override
	public int add() {
		// TODO Auto-generated method stub
		System.out.println("这个对宠物的   添加方法");
		return 1;
	}

	@Override
	public int update() {
		// TODO Auto-generated method stub
		System.out.println("这个对宠物的   更新方法");
		return 1;
	}

	@Override
	public int delete() {
		// TODO Auto-generated method stub
		System.out.println("这个对宠物的   删除方法");
		return 1;
	}

	@Override
	public List<?> select() {
		// TODO Auto-generated method stub
		System.out.println("这个对宠物的   查询方法");
		return new ArrayList<>();
	}

}

增强功能类:

public class Privilege {
	
	/**
	 * 实现用户的权限效验
	 */
	public Boolean checkPrivilege(Integer uid) {
		
		System.out.println("=====进行角色的权限验证=====");
		
		if(uid == 1 || uid == 2) {
			System.out.println("验证成功");
			return true;
		}else {
			System.out.println("验证失败");
			return false;
		}	
	}
}

产生代理对象进行封装:

public class ProxyTest {
	
	private static PetDao pet;
	private static Privilege pri;
	
	/**
	 * 完成属性的初始化
	 */
	public static void init(PetDao petDao , Privilege privilege) {
		pet = petDao;
		pri = privilege;
	}
	
	/**
	 * 定义方法产生动态 代理类的对象
	 */
	public static <T> T newProxyObject(Class<T> clazz) {
		//通过Proxy的静态方法获得代理对象
		/**
		 * 参数一: 类的加载器
		 * 参数二:指定代理对象需要实现的接口
		 * 参数三:拦截器对象,拦截代理对象调用的方法
		 */
		T t = (T)Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class[] {clazz}, new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				// TODO Auto-generated method stub
				Object result = null;
				//获得拦截的方法名
				String name = method.getName();
				//获得拦截方法的返回值
				Type returnType = method.getGenericReturnType();
				String type = returnType.getTypeName();
				
				if(name.startsWith("add") || name.startsWith("update") || name.startsWith("delete")) {
					//调用pri对的方法,实现  增强功能
					Boolean b = pri.checkPrivilege(0);
					//判断
					if(b) {
						//放行,权限效验通过
						result = method.invoke(pet, args);
					}
				}else {
					//直接放行,不需要进行权限的效验,    即不需要执行增强功能的方法
					 result = method.invoke(pet, args);
				}
				
				if(type.equals("int") && result== null) {
					return 0;
				}
				if(type.equals("java.util.List") && result == null) {
					return new ArrayList<>();
				}
				
				return result;
			}
		});
		return t;
	
	}
		
	public static void main(String[] args) {
		//进行属性的初始化
		ProxyTest.init( new PetDaoImpl(), new Privilege());
		
		//获得代理对象
		PetDao petDao = ProxyTest.newProxyObject(PetDao.class);
		//通过代理对象调用方法
		petDao.add();
		System.out.println("----------------------------");
		petDao.select();
	}
	
}

控制台显示:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值