代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 动态代理:在程序运行时,运用反射机制动态创建而成。静态代理
- 定义一个接口
package cn.itcast.proxy.sh;public interface PersonDao { public void savePerson(); public void updatePerson(); public void deletePerson();}
2、 目标类
package cn.itcast.proxy.sh;public class PersonDaoImpl implements PersonDao{ public void deletePerson() { System.out.println("delete person"); } public void savePerson() { System.out.println("save person"); } public void updatePerson() { System.out.println("update person"); }}
3、代理类,包含了目标类和一些额外的操作
package cn.itcast.proxy.sh;public class PersonDaoProxy implements PersonDao{ private PersonDao personDao; private Transaction transaction; public PersonDaoProxy(PersonDao personDao,Transaction transactions){ this.personDao = personDao; this.transaction = transactions; } public void deletePerson() { this.transaction.beginTransaction(); this.personDao.deletePerson(); this.transaction.commit(); } public void savePerson() { this.transaction.beginTransaction(); this.personDao.savePerson(); this.transaction.commit(); } public void updatePerson() { this.transaction.beginTransaction(); this.personDao.updatePerson(); this.transaction.commit(); }}
4、使用
package cn.itcast.proxy.sh;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class ProxyTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("cn/itcast/proxy/sh/applicationContext-proxy.xml"); PersonDao personDao = (PersonDao)context.getBean("personDao2"); personDao.deletePerson(); }}
静态代理的缺点
静态代理模式的缺点:
1、如果一个系统中有100Dao,则创建100个代理对象 2、如果一个dao中有很多方法需要事务,则代理对象的方法中重复代码还是很多 3、由第一点和第二点可以得出:proxy的重用性不强动态代理
1、产生的代理对象和目标对象实现了共同的接口
jdk动态代理 2、代理对象是目标对象的子类 hibernate: Person person = session.load(Person.class,1L); javassisit spring:cglib动态代理jdk的动态代理:
1、因为是用jdk的API做到的 2、代理对象是动态产生的 cglib产生的代理类是目标类的子类注意事项:
1、拦截器中invoke方法体的内容就是代理对象方法体的内容 2、当客户端执行代理对象.方法时,进入到了拦截器的invoke方法体 3、拦截器中invoke方法的method参数是在调用的时候赋值的jdk动态代理
定义一个接口
package cn.itcast.jdkproxy.sh;public interface PersonDao { public void savePerson(); public void updatePerson(); public void deletePerson();}
目标类
package cn.itcast.jdkproxy.sh;public class PersonDaoImpl implements PersonDao{ public void deletePerson() { System.out.println("delete person"); } public void savePerson() { System.out.println("save person"); } public void updatePerson() { System.out.println("update person"); }}
拦截器
package cn.itcast.jdkproxy.sh;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * 拦截器 * @author Think * 1、引入目标类 * 2、引入事务 * 3、通过构造函数给目标类和事务赋值 * 4、填充invoke方法 * */public class PersonInterceptor implements InvocationHandler{ private Object target;//目标类 private Transaction transaction;//引入事务 public PersonInterceptor(Object target,Transaction transaction){ this.target = target; this.transaction = transaction; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub this.transaction.beginTransaction(); method.invoke(this.target, args);//调用目标类的方法 this.transaction.commit(); return null; }}
使用
package cn.itcast.jdkproxy.sh;import java.lang.reflect.Proxy;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class ProxyTest { @Test public void test(){ Object target = new PersonDaoImpl(); Transaction transaction = new Transaction(); PersonInterceptor interceptor = new PersonInterceptor(target, transaction); /** * 1、目标类的类加载器 * 2、目标类实现的所有的接口 * 3、拦截器 */ PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); personDao.deletePerson(); }}
cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
目标类
package net.battier.dao.impl; /** * 这个是没有实现接口的实现类 * * @author student * */ public class BookFacadeImpl1 { public void addBook() { System.out.println("增加图书的普通方法..."); } }
拦截类
package net.battier.proxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 使用cglib动态代理 * * @author student * */ public class BookFacadeCglib implements MethodInterceptor { private Object target; /** * 创建代理对象 * * @param target * @return */ public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回调方法 enhancer.setCallback(this); // 创建代理对象 return enhancer.create(); } @Override // 回调方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("事物开始"); proxy.invokeSuper(obj, args); System.out.println("事物结束"); return null; } }
使用
package net.battier.test; import net.battier.dao.impl.BookFacadeImpl1; import net.battier.proxy.BookFacadeCglib; public class TestCglib { public static void main(String[] args) { BookFacadeCglib cglib=new BookFacadeCglib(); BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); bookCglib.addBook(); } }