代理模式是常用的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 {@Testpublic 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;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubthis.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 {@Testpublic 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(); }
}
参考链接
java动态代理(JDK和cglib) - C’est la vie - 博客园