01.什么是代理模式?
解析:代理(Proxy):代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,
而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。
这些额外的操作通常需要与实际对象进行通信。
02.代理的组成都有什么?
解析:由三部分组成,分别是:抽象对象(Subject 接口),真实对象(RealSubject 实现了Subject接口),代理对象(ProxySubject)
03.代理对象作用场景?
解析:
第一,远程代理,也就是为一个对象在不同的地址空间提供局部代表.这样可以隐藏一个对象存在于不同地址空间的事实[DP]
第二:需补代理,是根据需要创建开销很大的对象.通过它来存放实例化需要很长时间的真实对象[DP].这样就可以达到性能的最优化.
04.代理有几种?
解析:代理有两种类型,即 动态代理和静态代理,
动态代理:动态代理,在Struts和Spring等框架中都用到了动态代理,用于帮助程序员生成其要使用的类的子类或本类,这样框架就可以再代码之前做一些动作,
比如前置方法增强,后置方法增强,记录日志,异常捕获等等.在程序运行时运用反射机制动态创建而成
(插: AOP(AspectOrientedProgramming):将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,
我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码---解耦。)
静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态代理 VS 静态代理:
静态代理类优缺点
优点:
代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)
缺点:
1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,
除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
如上的代码是只为UserManager类的访问提供了代理,但是如果还要为其他类如Department类提供代理的话,就需要我们再次添加代理Department的代理类。
静态代理---------->案列
01.创建一个接口:
package cn.work.proxy; //抽象对象 public interface Subject { public String request(); }
02.创建一个实现类:
package cn.work.proxy; //真实对象 public class RealSubject implements Subject { public String request() { return "真实对象"; } }
03.创建一个代理对象:
package cn.work.proxy; public class ProxySubject { //把抽象对象组成代理对象的字段 private Subject sub; public Subject getSub() { return sub; } public void setSub(Subject sub) { this.sub = sub; } public String reqString(){ System.out.println("代理增强"); return sub.request(); } }
04.创建Test测试类:
//对象代理 @Test public void test09() { Subject sub=new RealSubject(); ProxySubject ps=new ProxySubject(); ps.setSub(sub); System.out.println(ps.reqString()); }
动态代理优点:
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,
在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强
动态代理--------->实例
01.创建一个DAO接口
package cn.work.dao; import cn.work.entity.User; public interface UserDao { public void add(User user); }
02.创建一个DAO接口的实现
package cn.work.dao; import cn.work.entity.User; public class UserImpl implements UserDao{ public void add(User user) { System.out.println("sava success"); } }
03.创建测试类
@Test public void test10(){ User user=new User(); final UserDao userDao=new UserImpl(); UserDao u =(UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代码增强"); return method.invoke(userDao, args); } } ); u.add(user); }
参数说明:
Proxy.newProxyInstance(loader, interfaces, h)
loader:类加载器,传入你要代理的对象,通过 对象名.getClass().getClassLoader()来拿到该对象的类加载器.
interfaces:被代理对象的所有实现接口的集合
InvocationHandler 是代理实例的调用处理程序 实现的接口
实现InvcationHandler的米明内部类,
new InvcationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
...... return ....; }
}