1)代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式,即通过代理访问目标对象.
2)代理的好处:可以在目标对象实现的基础上,增加额外的功能操作,即扩展目标对象的功能.
3)分类:静态代理,动态代理,cglib代理.
4)代理模式的关键点:代理对象与目标对象.
5)举例:商家是直接联系不到明星的,一般情况下,都是商家找明星经纪人,然后明星经纪人通知明星.明星是目标对象,明星经纪人就是代理对象.
1)要点:代理对象要实现与目标对象一样的接口.
2)举例:模拟保存用户
UserDao-->直接保存
UserDaoProxy-->给保存方法添加事务管理
3)接口:IUserDao.java
public interface IUserDao { void save(); } 4)目标对象:UserDao.java,实现了IUserDao接口 public class UserDao implements IUserDao { @Override public void save() { System.out.println("***保存用户数据到数据库"); } }5)代理对象:UserDaoProxy.java,与目标对象一样实现了IUserDao接口 public class UserDaoProxy implements IUserDao{ private IUserDao target; public UserDaoProxy(IUserDao target) { this.target = target; } @Override public void save() { System.out.println("开启事务..."); //执行目标对象的方法 target.save(); System.out.println("提交事务..."); } }6)测试: public class App { @Test public void testProxy() throws Exception { IUserDao userDao=new UserDao(); UserDaoProxy proxy=new UserDaoProxy(userDao); proxy.save(); } } 结果: 开启事务... ***保存用户数据到数据库 提交事务...综上,扩展了UserDao的save接口.7)总结静态代理:
a)优点:可以做到在不修改目标对象的前提下,对目标对象的功能进行扩展.
b)缺点:因为代理对象需要与目标对象实现一样的接口,所以会造成很多代理类,类太多;一旦接口增加方法,目标对象与代理对象都要维护.(动态代理就可以避免这些问题,借助代理工厂完成)
1)代理对象不需要实现接口.
2)代理对象的生成利用了JDK API,动态地在内存中构建代理对象(需要我们指定创建代理对象 目标对象 实现的接口的类型)
3)动态代理也叫JDK代理,或者接口代理.
4)接口和目标对象还是用上面代码,代理工厂代码如下:
package com.bighuan.b_dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 给所有Dao创建代理对象(动态代理) * * @author bighuan * */ public class ProxyFactory { // 维护一个目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } // 给目标对象生成代理对象 public Object getProxyInstance() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),// 得到目标对象实现的接口类型 // new Class[]{IUserDao.class} new InvocationHandler() {// 事件处理器 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 开启事务 System.out.println("***开启事务***"); String name = method.getName();// 拿到方法名 System.out.println(name); // 执行目标对象方法 Object returnValue = method.invoke(target, args); // 提交事务 System.out.println("***提交事务***"); return returnValue; } }); } } 5)测试: @Test public void testProxy() throws Exception { //目标对象 IUserDao userDao=new UserDao(); //原始类型:class com.bighuan.b_dynamic.UserDao System.out.println(userDao.getClass()); //给目标对象创建代理对象 IUserDao proxy=(IUserDao) new ProxyFactory(userDao).getProxyInstance(); //class $Proxy4,内存中动态生成的代理对象 System.out.println(proxy.getClass()); //执行方法[代理对象] proxy.save(); }效果和上面的静态代理一致,但却规避了静态代理的缺点.6)动态代理总结:代理对象不需要实现接口,但是目标对象一定要实现接口;否则不能使用动态代理!
如果一个目标对象需要实现功能扩展,但是目标对象却没有实现接口,该怎样实现功能扩展呢?
1)Cglib代理也叫子类代理,在内存中构建一个子类对象从而实现对目标对象的功能扩展.
2)JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口.如果想代理没有实现接口的类,就可以使用CGLIB实现. 3)CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截). 4)CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
5)开发准备:需要引入Cglib的相关jar文件,但是Spring的核心包中已经包括了cglib功能,所以自接导入spring-core-3.2.5.jar即可;引入功能包后,就可以在内存中动态构建子类.
6)代理类不能为final类(final类没有子类),目标对象的方法如果为final或static(final或static修饰的方法,子类不能重写),那么就不会拦截,即不会执行除目标对象之外的业务方法.
7)UserDao.java
public class UserDao { public void save() { System.out.println("***保存用户数据到数据库"); } }ProxyFactory.java package com.bighuan.c_cglib; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; /** * Cglib子类代理工厂 * (对UserDao,在内存中动态构建一个子类对象) * @author bighuan * */ public class ProxyFactory implements MethodInterceptor{ //维护目标对象 private Object target; public ProxyFactory(Object target){ this.target=target; } //给目标对象创建代理对象 public Object getProxyInstance(){ //1,工具类 Enhancer hancer=new Enhancer(); //2,设置父类 hancer.setSuperclass(target.getClass()); //3,设置回调函数 hancer.setCallback(this); //4,创建子类(代理对象) return hancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("**********开启事务*****"); //执行目标对象的方法 Object returnValue = method.invoke(target, args); System.out.println("**********提交事务*****"); return returnValue; } } 8)测试: @Test public void testProxy() throws Exception { //目标对象 UserDao target=new UserDao(); //class com.bighuan.c_cglib.UserDao System.out.println(target.getClass()); //代理对象 UserDao proxy=(UserDao) new ProxyFactory(target).getProxyInstance(); //class com.bighuan.c_cglib.UserDao$$EnhancerByCGLIB$$b6d37fe1 System.out.println(proxy.getClass()); //执行代理对象的方法 proxy.save(); }结果: **********开启事务***** ***保存用户数据到数据库 **********提交事务*****下一篇,Spring的AOP编程,期待吧,boys!