跟着步骤来:
1、首先创建一个UserDao接口
public interface UserDao {
public void add();
public void delete();
public void search();
public void change();
}
2、创建一个UserDaoImpl实现类
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("添加了一个学生");
}
@Override
public void delete() {
System.out.println("删除了一个学生");
}
@Override
public void search() {
System.out.println("查找一个学生");
}
@Override
public void change() {
System.out.println("修改一个学生");
}
}
3、编写一个客户端测试类
public class Client {
public static void main(String[] args) {
UserDao ud = new UserDaoImpl();
ud.add();
ud.delete();
ud.change();
ud.search();
}
}
4、分析一
此时运行程序,结果:
添加了一个学生
删除了一个学生
修改一个学生
查找一个学生
没有问题。
但是此时用户增加需求了:希望对每一个操作增加权限控制功能和日志记录功能。最最最简单的方法就是如下:
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("我是权限控制");
System.out.println("添加了一个学生");
System.out.println("我是日志记录");
}
@Override
public void delete() {
System.out.println("我是权限控制");
System.out.println("删除了一个学生");
System.out.println("我是日志记录");
}
@Override
public void search() {
System.out.println("我是权限控制");
System.out.println("查找一个学生");
System.out.println("我是日志记录");
}
@Override
public void change() {
System.out.println("我是权限控制");
System.out.println("修改一个学生");
System.out.println("我是日志记录");
}
}
这是非常繁琐的。如果使用静态代理来实现呢?如果有多个UserDao来操作,那就需要多个代理类去代理这些UserDao,显然也是比较复杂的。
因此动态代理出现了。
5、实现动态代理
/**
* 代理对象调用的处理程序
*/
public class MyInvocationHandler implements InvocationHandler {
private Object target; //目标对象
public MyInvocationHandler(Object obj){ //有参构造
this.target = obj;
}
/**
* 代理类要实现的功能
* @param proxy 代理对象
* @param method 代理实例上调用的方法接口
* @param args 接口中的参数,没有就为null
* @return 返回一个代理对象
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----权限校验----");
Object result = method.invoke(target, args); //这里采用了反射中的Methed方法
System.out.println("----日志记录----");
return result;
}
}
//完善客户端类
public class Client {
public static void main(String[] args) {
UserDao ud = new UserDaoImpl();
ud.add();
ud.delete();
ud.change();
ud.search();
//如果此时,我想要对每一个操作增加权限和日志记录功能,那么就需要在响应的功能模块上添加,会比较复杂
//因此这里创建一个代理对象,让代理对象来做权限和日志功能。
/*********************************************************************/
//对ud对象做一个代理
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(ud);
/**
* 第一个参数: 需要代理的对象的类加载器
* 第二个参数: 需要被代理对象实现的方法接口
* 第三个参数: 代理对象
* 返回值: 需要代理的对象类型
*/
UserDao proxy = (UserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(),
ud.getClass().getInterfaces(), myInvocationHandler);
//使用代理对象来执行上述需求
proxy.add();
proxy.delete();
proxy.change();
proxy.search();
}
6、分析二
-
UserDao ud = new UserDaoImpl();
首先创建一个需要被代理的对象 ud -
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(ud);
通过我们自定义的构造方法对ud对象做一个代理。MyInvocationHandler
是代理对象需要执行的附属操作。内部实现了InvocationHandler
接口中的Invoke
方法,方法内执行操作。 -
(UserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), myInvocationHandler);
通过Proxy类,实例化一个代理实例,具体参数见上方代码。代理实例运行时,会去执行myInvocationHandler
中的invoke
方法! -
使用代理实例来执行业务,此时代理实例运行,
invoke
执行,看结果:
----权限校验----
添加了一个学生
----日志记录----
----权限校验----
删除了一个学生
----日志记录----
----权限校验----
修改一个学生
----日志记录----
----权限校验----
查找一个学生
----日志记录----
符合我们的真实需求。
总结一下优点
个人觉得最主要的一个优点就是解耦。我们可以通过动态代理来实现一些业务接口方法以外的附属方法,并且与业务接口的耦合度很低,降低了修改需求的成本。
(个人理解,初学,有错误希望大牛们指出!!)