摘要:本文主要向大家介绍了JAVA语言设计模式之结构型代理模式详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。
本文主要向大家介绍了JAVA语言设计模式之结构型代理模式详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。
主要分静态代理和动态代理
1、静态代理:
首先我们看下为什么要使用动态代理,先看看静态代理有什么问题。
演示一个静态代理的例子:(jdk的代理是基于接口的)
功能就是,保存数据的时候添加事务处理
//定义接口 PersonDao.java
public interface PersonDao {
public void savePerson();
}
//定义个实现类 PersonDaoImpl.java
public class PersonDaoImpl implements PersonDao{
public void savePerson() {
System.out.println("save person");
}
}
//定义一个事务类 Transaction.java
public class Transaction {
public void beginTransaction(){
System.out.println("begin transaction");//开启事务
}
public void commit(){
System.out.println("commit");//提交事务
}
}
//定义个代理类 PersonDaoProxy.java
public class PersonDaoProxy implements PersonDao{ //实现相同的接口
private PersonDao personDao;
private Transaction transaction;
public PersonDaoProxy(PersonDao personDao,Transaction transaction) {
super();
this.personDao = personDao;//通过构造传进来
this.transaction = transaction;
}
public void savePerson() {
this.transaction.beginTransaction();
this.personDao.savePerson();
this.transaction.commit();
}
}
//测试 ProxyTest.java
public class ProxyTest {
@Test
public void testProxy(){
PersonDao personDao = new PersonDaoImpl();
Transaction transaction = new Transaction();
PersonDaoProxy proxy = new PersonDaoProxy(personDao, transaction);
proxy.savePerson();
}
}
看看静态代理有什么问题:
a.静态代理没有事务重用,我们还是要在每个方法里面调用this.transaction.beginTransaction();
b.如果我们dao层有100个方法,我们就需要写100个proxy类,变得更麻烦了。接口中定义了多少个方法,
proxy也要实现多少个方法。
c.如果一个proxy实现了多个接口,如果其中的一个接口发生变化(添加了一个方法),那么proxy也要做相应的改变。
所以静态代理我们维护起来会更加的麻烦。
2、动态代理:
既然静态代理这么多的问题,那么我们看看动态代理。
顾名思义,动态代理就是动态生成Proxy类,不需要我们自己创建Proxy了。
演示下:
public interface PersonDao {
public void savePerson();
public void updatePerson();
}
public class PersonDaoImpl implements PersonDao{
public void savePerson() {
System.out.println("save person");
}
public void updatePerson() {
System.out.println("update person");
}
}
public class Transaction {
public void beginTransaction(){
System.out.println("begin transaction");
}
public void commit(){
System.out.println("commit");
}
}
//最主要的设置拦截器
public class MyInterceptor implements InvocationHandler{
private Object target;//目标类
private Transaction transaction;
public MyInterceptor(Object target, Transaction transaction) {
super();
this.target = target;
this.transaction = transaction;
}
//proxy这个是代表的我们MyInterceptor这个类,千万别写成method.invoke(proxy);
//否则就死循环,jvm就挂了
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if("savePerson".equals(methodName)||"updatePerson".equals(methodName)
||"deletePerson".equals(methodName)){
this.transaction.beginTransaction();//开启事务
method.invoke(target);//调用目标方法
this.transaction.commit();//事务的提交
}else{
method.invoke(target);
}
return null;
}
}
//使用
public class JDKProxyTest {
@Test
public void testJDKProxy(){
Object target = new PersonDaoImpl();
Transaction transaction = new Transaction();
MyInterceptor interceptor = new MyInterceptor(target, transaction);
/**
* 参数说明:
* 1、目标类的类加载器
* 2、目标类实现的所有的接口
* 3、拦截器
*/
PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), interceptor);
//personDao.savePerson();
personDao.updatePerson();
}
}
注意几个问题:
a、拦截器的invoke方法是在时候执行的?
当在客户端,代理对象调用方法的时候,进入到了拦截器的invoke方法。
b、代理对象的方法体的内容是什么?
拦截器的invoke方法的内容就是代理对象的方法的内容
c、拦截器中的invoke方法中的参数method是谁在什么时候传递过来的?
代理对象调用方法的时候,进入了拦截器中的invoke方法,所以invoke方法中的参数method就是
代理对象调用的方法。
我们看看动态代理有什么问题:
a.在拦截器中除了能调用目标对象的目标方法以外,功能是比较单一的,在这个例子中只能处理事务。
这里可以有个解决方案。比如我们有 Transaction(事务),Log(打印),Access(权限控制)
我们可以让这几个类同时实现一个接口,我们传一个接口的List过来,然后for循环处理。
这也是种解决方案。
b.拦截器中的invoke方法的if判断方法名称在真实的开发环境下是不靠谱的,
因为一旦方法很多if语句需要写很多。
我有100个方法就要判断100次,而且名称不能写错。
这个暂时没有好的解决方法,在spring中可以解决。
c.调用时机的问题,我们是在invoke方法之前调用还是在invoke方法之后调用,或者是出异常在调用。
3、基于动态代理中的第一个问题,解决方案:
//给事务、日志等做了一个抽象,而这个抽象就是Interceptor
public interface Interceptor {
public void interceptor();
}
//事务实现了接口,其他的也同样的做法
public class Transaction implements Interceptor{
public void interceptor() {
System.out.println("begin transaction");
System.out.println("commit");
}
}
//拦截器传的是一个 List<interceptor>
public class MyInterceptor implements InvocationHandler{
private Object target;//目标类
//除了目标类以外的所有的功能都抽象为Interceptor
private List<interceptor> interceptors;
public MyInterceptor(Object target, List<interceptor> interceptors) {
super();
this.target = target;
this.interceptors = interceptors;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
for (Interceptor interceptor : interceptors) {//这样调用了多个功能方法
interceptor.interceptor();
}
method.invoke(target);
return null;
}
}
//使用
@Test
public void testJDKProxy(){
/**
* 1、创建一个目标对象
* 2、创建一个事务
* 3、创建一个拦截器
* 4、动态产生一个代理对象
*/
Object target = new PersonDaoImpl();
Transaction transaction = new Transaction();
List<interceptor> interceptors = new ArrayList<interceptor>();
interceptors.add(transaction);//我们可以添加不同的interceptor
MyInterceptor interceptor = new MyInterceptor(target, interceptors);
PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), interceptor);
personDao.updatePerson();
}
</interceptor></interceptor></interceptor></interceptor></interceptor>
4、cglib动态代理:
我们上面说的是jdk的动态代理,是基于接口的,我们的目标类需要实现接口,代理类就实现相同的接口。
cglib代理是基于子类的。
演示下:
//首先需要导入cglib的包
cglib-nodep-2.1_3.jar
//我们现在就没有接口了
public class PersonDaoImpl{
public void savePerson() {
System.out.println("save person");
}
public void updatePerson() {
System.out.println("update person");
}
}
public class Transaction {
public void beginTransaction(){
System.out.println("begin transaction");
}
public void commit(){
System.out.println("commit");
}
}
//我们的拦截器
public class MyInterceptor implements MethodInterceptor{
private Object target;//目标类
private Transaction transaction;
public MyInterceptor(Object target, Transaction transaction) {
super();
this.target = target;
this.transaction = transaction;
}
public Object createProxy(){
//代码增强类
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);//参数为拦截器
enhancer.setSuperclass(target.getClass());//生成的代理类的父类是目标类
return enhancer.create();
}
public Object intercept(Object arg0, Method method, Object[] arg2,
MethodProxy arg3) throws Throwable {
this.transaction.beginTransaction();
method.invoke(target);
this.transaction.commit();
return null;
}
}
//使用
//通过cglib产生的代理对象,代理类是目标类的子类
public class CGLibProxyTest {
@Test
public void testCGlib(){
Object target = new PersonDaoImpl();
Transaction transaction = new Transaction();
MyInterceptor interceptor = new MyInterceptor(target, transaction);
//使用拦截器创建一个代理的对象
PersonDaoImpl personDaoImpl = (PersonDaoImpl)interceptor.createProxy();
personDaoImpl.savePerson();
}
}
使用cglib的好处是我们目标类不需要实现接口就可以完成动态代理功能了。
讲了这么多,还是没解决多if判断等问题。
希望对JAVA有兴趣的朋友有所帮助。了解更多内容,请关注职坐标编程语言JAVA频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号