您的位置:首页 > 编程语言 > Java开发

JAVA中的动态代理和AOP编程思想

2016-10-21 15:19 295 查看

1.代理模式

什么是代理模式及其作用

ProxyPattern(即:代理模式),23种常用的面向对象软件的设计模式之一代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

只是看上面的概念陈述可能不太好理解。好比潘金莲和西门庆的故事一样,众所周知,潘金莲是武大郎的老婆,但是却和西门庆看对了眼儿,但是潘金莲很苦恼,如何才能向西门庆表达自己的心思呢?自己已是有夫之妇。于是她找到了王婆,王婆代她向西门庆传达心意。这个故事里,王婆就是“代理对象”。

生活中,有很多代理的例子,和代理模式的思想是一样的,好比我们去找房子,我们拜托房屋中介,这里中介就是代理对象,中介去找房子,但是最后房子却是属于我们的。这就代理的含义。

优点:

(1).职责清晰

真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是 编程简洁清晰。

(2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的作用。

(3).高扩展性

结构

一个是真正的你要访问的对象(目标类),另一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。

我们可以一组代码案例加深对代理的理解。还是回到上文所提及的西门庆和潘金莲的故事中。

从前有一种女人,这种女人水性杨花,喜欢抛媚眼

/**
* 喜欢抛媚眼的女人
* @author Keo.Zhao
*
*/
public interface KindWomen {

public void throwEyes();
public void doSomething();
}


有个叫潘金莲(目标类)的女人,恰好就是这种KindWomen

/**
* 这是潘金莲
* @author Keo.Zhao
*
*/
public class PJL implements KindWomen{

public void throwEyes(){
System.out.println("潘金莲抛媚眼");
}

public void doSomething(){
System.out.println("潘金莲...");
}
}


潘金莲看上了西门庆,但是自己已是有夫之妇,怎样才能与西门庆邂逅呢?思前想后,她找了王婆(代理类),王婆和她是一类(KindWomen)女人(真正对象与代理对象实现同一个接口)

/**
* 王婆
* @author Keo.Zhao
*
*/
public class WP implements KindWomen{

private KindWomen kindWomen;
public WP(KindWomen kindWomen){
this.kindWomen = kindWomen;
}
@Override
public void throwEyes() {
kindWomen.throwEyes();

}

@Override
public void doSomething() {
kindWomen.doSomething();

}

}


好了,故事里的三个角色,现在就剩西门庆没出场了。

/**
 * 西门庆
 * @author Keo.Zhao
 *
 */
public class XMQ {

    public static void main(String[] args) {
        //潘金莲实例
        KindWomen pjl = new PJL();
        //王婆实例
        KindWomen wp = new WP(pjl);
        
        wp.throwEyes();
    }
    
}


最后打印结果



可以看出,虽然是王婆(代理类)执行了throwEyes()抛媚眼方法,但是最后西门庆接收到的,还是来自于潘金莲(目标类)的。

这就是一个静态代理的例子。

2.动态代理

上文我已经初步认识了代理模式,现在我们要开始学习动态代理。

动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。

动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理对象 (spring学习)

动态代理中,不再需要代理类,也就是说之前故事里的王婆,将没有存在的必要。可以这么理解,时代终究在发展,如今已经是信息化的时代了,微信上一条消息,多远都可以传递,微信取代了王婆,它是一个虚拟平台,本质上就是一个动态代理对象。

动态代理生成技术:

1.jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象。

2.cglib (spring中的类库)

Java.lang.reflect.Proxy类可以直接生成一个代理对象

查询API帮助文档,我们可以得到以下讯息:

Proxy.newProxyInstance():产生代理类的实例。仅能代理实现至少一个接口的类

ClassLoader:类加载器。固定写法,和被代理类使用相同的类加载器即可。

Class[] interface:代理类要实现的接口。固定写法,和被代理类使用相同的接口即可。

InvocationHandler:策略(方案)设计模式的应用。如何代理?

InvocationHandler中的invoke方法:调用代理类的任何方法,此方法都会执行

Object proxy:代理对象本身的引用。一般用不着。

Method method:当前调用的方法。

Object[] args:当前方法用到的参数

动态代理实例代码:

public static void main(String[] args) {
        //马蓉实例
        final MR mr = new MR();
        
        KindWomen proxy
        = (KindWomen) Proxy.newProxyInstance(mr.getClass().getClassLoader(),
                                                 mr.getClass().getInterfaces(),
                                                 new InvocationHandler() {
                                                    @Override
                                                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                                        
                                                        Object o = method.invoke(mr, null);
                                                        return o;
                                                    }
                                                });
        proxy.throwEyes();
    }
   


从上述代码,我们可以看出,已经不用关心这个代理对象是谁了,代理对象是动态生成的。JVM拿到了真实对象的字节码对象(mr.getClass().getClassLoader()),也拿到了其接口(mr.getClass().getInterfaces()),在内存中动态创建了我们的代理对象。本质上,你可以理解为,动态代理对象是其真实对象的一个山寨版本。

代理对象的目的,实际上就是为真实对象做事情,以及起到一定的拦截作用(通过改变 Object[] args:当前方法用到的参数,传递给真实对象的参数)。事实上,我们可以在这句代码之前之后做一些事情,好比如下:

public static void main(String[] args) {
//马蓉实例
final MR mr = new MR();

KindWomen proxy
= (KindWomen) Proxy.newProxyInstance(mr.getClass().getClassLoader(),
mr.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事物");
Object o = method.invoke(mr, null);
System.out.println("结束事物");
return o;
}
});
proxy.throwEyes();
}


这就是AOP思想 —— 面向切面编程。

3.AOP编程思想

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容(Spring核心之一),是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。



光是看概念陈述并不好理解这个所谓的“面向切面编程”。我们把目光放在上图。前端的UI界面,向后台发送请求,control(web)层接收到了前台传过来的数据,再传到service层,service层经过一些列的逻辑代码,再调用Dao层的方法

。看图我们不难发现,Service层被两条箭头线横截了,你可以在这两条箭头的位置分别写两个方法,一个在Service的逻辑代码发生之前写,一个在其发生之后写。所以,你可以认为Service被这两条线,截出了两个切面,你所写的两个方法是在这个切面上写的,我们正面对着这个切面编程。这就是我们的AOP——面向切面编程。

而在实际的编码中,我们又是如何实现切面编程的呢?没错,就是上文所提及的动态代理!我们来看一个例子,加深对其理解。

public class ObjectFacoty {

public static Object getUserService(){
//目标类
UserService userService = new UserServiceImpl();
//代理类
UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = null;
try {
System.out.println("开始事务");
invoke = method.invoke(userService,null);
System.out.println("提交事务");
} catch (Exception e) {
System.out.println("回滚事务");
e.printStackTrace();
}
return invoke;
}
});
return proxy;

}
}


这只是一个很简单的例子,如果想要加深对AOP面向切面思想的理解与应用,可以深入学习一下Spring框架。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java proxy aop 动态代理