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

从JDK动态代理看Spring之AOP实现(转帖)

2008-10-18 01:08 826 查看
Spring 缺省使用J2SE 动态代理(dynamic proxies ) 来作为AOP 的代理。这样任何接口都可以被代理。

Spring 也支持使用CGLIB 代理. 对于需要代理类而不是代理接口的时候CGLIB 代理是很有必要的。 如果一个业务对象并没有实现一个接口,默认就会使用CGLIB 。------- 这是Spring Framework 开发手册中对AOP 的一个简要概括

其实个人看来 Spring Framework 是个大杂烩,它提供了许多框架的接口。当然它自己也有一套 MVC 框架。其中最为常见也最为重要也就是 IoC 和 AOP 。所谓的 LightWeight Container( 轻量级 ) 就是整个容器的倾入性极低或者没有倾入性让对象与对象之间的关系通过配置来体现避免了对象之间的直接调用 ( 当然这不是轻量级容器的完全定义 ), 轻量级带来的就是单例和工厂的有效减少。嗯 …IoC 是一种思想,它的实现有依赖注入和依赖查找。开发中遇到比较多的就是依赖注入 Spring 所提供的方法有 (Setter 方法注入,构造器注入 以及接口注入 ) 三种方法的使用程度也如我所列的顺序一样,当然各人所好不同。
AOP 就是面向切面编程,平时我们所面对的都是 OO 那是一个纵向的编程思想,而 AOP 的出现使得面向的切面 ( 即横向编程 ) 的理念得到了众多的认可。其实 AOP 的思想早期在 EJB( 个人对 EJB 了解不是很够,这里就不在细说 ) 中也得以体现,最为常用的就是声明式事务的使用。 For Example :比如我声明这个类中所有以 save 开头的接口都用事务,所以当其被调用时开启事务,成功后提交事务,失败了就回滚事务。那 Spring 中所提供的 AOP 与 EJB 中的所采用的拦截机制有什么区别呢?对早期的 EJB(3.0 之前 ) 来说,你只有实现了 EJB 才有该功能而 Spring 则不同, Spring 对普通的 POJO 都可以实现 AOP 。这就是为什么 EJB2.x 以失败而告终,所以当 EJB3.0 卷土重来时它就加入对 Spring 的集成。这也是开源的一大优势呐。
一下说的有点多了,吐出来的知识点可能也多了点。还是回归主题吧。谈谈 AOP : Spring 中默认是通过 JDK 动态代理来是 AOP 。其实你要是对 JDK 动态代理理解烂熟于心我想我下面的内容你是不用看了。如果你还是不怎么熟悉,希望大家一起学习。我把自己学习 AOP 的心得写一写,以示例为主便于理解,讲的不好还希望大家指点指点 …..
JDK 动态代理分静态代理和动态代理,其中静态代理适用于代理比较少的情形它是一个实实在在的代理类所以当代理比较多的时候你得去编写许多代理类效率自然就下降了。而动态是在运行时才生产的,当你调用时才生成代理当然它的前提是继承接口 (invocationHandler) 实现 invoke() 方法。下面我们看个动态代理的例子:(一个很普通的 JAVA PROJECT )



这个 project 中,我写了:一个接口: UserManagery
接口的实现类: UserManageryImpl
代理类: SecurityHandler
以及一个简单的客户端: Client

先看接口:很普通,就是几个方法。

Java代码



package com.jummy.spring;

public interface UserManager {

public void addUser(int id,String name);

public void delUser(int id);

public void modifyUser(int id,String name,int age);

}
package com.jummy.spring;

public interface UserManager {
public void  addUser(int id,String name);
public void delUser(int id);
public void modifyUser(int id,String name,int age);
}

接着看实现类:也很普通,各个方法的具体实现。

Java代码



package com.jummy.spring;

public class UsreManagerImpl implements UserManager {

public void addUser(int id, String name) {

/*

* 比如说要在添加之前做一些安全性检查,当然最原始的做法时在调用方法之前写一些验证代码。 Of

* course你可以将验证专门抽取出来写成一个方法甚至一个类,然后进行调用。 For example

* 该类中抽取出一个scurity()的方法用于验证,不过你每次验证都需要如下的调用

* 如此来若需要的调用的方法多了,方法甚至类就不再单一了。甚至一眼看不出这到底是一个具体功能模块

* 还是验证模块。这样类就不再便于管理(方法太多)。于是就出现了代理,通过代理类来实现那些不是主要的功能

* 这样模块的功能就很清晰,同时你在不修改原先类的情况下给该类添加功能实现

*/

// security();

System.out.println("---UsreManagerImpl中的addUser方法的实现-----");

}

public void delUser(int id) {

System.out.println("-----delUser方法的实现-----");

}

public void modifyUser(int id, String name, int age) {

System.out.println("----modifyUser方法的实现-----");

}

public void security() {

System.out.println("-----调用security方法-------");

}

}
package com.jummy.spring;

public class UsreManagerImpl implements UserManager {

public void addUser(int id, String name) {
/*
* 比如说要在添加之前做一些安全性检查,当然最原始的做法时在调用方法之前写一些验证代码。 Of
* course你可以将验证专门抽取出来写成一个方法甚至一个类,然后进行调用。 For example
* 该类中抽取出一个scurity()的方法用于验证,不过你每次验证都需要如下的调用
* 如此来若需要的调用的方法多了,方法甚至类就不再单一了。甚至一眼看不出这到底是一个具体功能模块
* 还是验证模块。这样类就不再便于管理(方法太多)。于是就出现了代理,通过代理类来实现那些不是主要的功能
* 这样模块的功能就很清晰,同时你在不修改原先类的情况下给该类添加功能实现
*/
// security();
System.out.println("---UsreManagerImpl中的addUser方法的实现-----");
}

public void delUser(int id) {
System.out.println("-----delUser方法的实现-----");
}

public void modifyUser(int id, String name, int age) {
System.out.println("----modifyUser方法的实现-----");
}

public void security() {
System.out.println("-----调用security方法-------");
}
}

只是此时提及一下代理的作用,比如说我在调用 ADD() 方法之前需要进行安全验证(这是个很常规的步骤)传统的编码方式就是将验证方法直接写在类中,当然这无可厚非但是当需要调用的方法不断增加时整个类的就会很模糊。有人说我将需要验证的方法单独抽象出来成一个类。但这样你也要在原来的类中不断的用实例化这个验证类,这也存在所需方法不断增多的情况。这样我们就考虑 又要调用验证又要不去破坏(修改)原来类的代码。所以代理就粉墨登场,通过一个代理类来实现这个功能。
看一下代理类:这是关键,理解这个你就理解了 AOP 了

Java代码



package com.jummy.spring;

/*

* 创建一个专门的执行security方法的类。实现InvocationHandler接口

*

*

*

*

*/

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

public class SecurityHandler implements InvocationHandler {

//适合于所有的对象

private Object object;

//通过构造方法将参数传递

public Object newProxy(Object object){

this.object=object;

//生成动态代理 3个参数

return Proxy.newProxyInstance(object.getClass().getClassLoader(),

object.getClass().getInterfaces(),

this);

}

public Object invoke(Object arg0, Method method, Object[] arg2)

throws Throwable {

//代理类在调用任何方法都先调用invoke()方法,这里的invoke()方法中先执行checkSecurity()方法

checkSecurity();

//这里可以查看invoke中调用方法的名称

System.out.println("method name="+method.getName());

//该参数是一个数组类型Object[] arg2

for(int i=0;i<arg2.length;i++){

System.out.println(arg2[i]);

}

Object result=null;

//下面才是真正调用的方法,将对象添加到invoke 方法中

try{

result=method.invoke(object, arg2);

//方法执行之后,也可以自定义方法

}catch(Exception e){

e.printStackTrace();

}

return result;

}

public void checkSecurity(){

System.out.println("-----checkSecurity------");

}

}
package com.jummy.spring;
/*
* 创建一个专门的执行security方法的类。实现InvocationHandler接口
*
*
*
*
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class SecurityHandler implements InvocationHandler {
//适合于所有的对象
private Object object;

//通过构造方法将参数传递
public Object newProxy(Object object){
this.object=object;
//生成动态代理 3个参数
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
this);
}
public Object invoke(Object arg0, Method method, Object[] arg2)
throws Throwable {
//代理类在调用任何方法都先调用invoke()方法,这里的invoke()方法中先执行checkSecurity()方法
checkSecurity();
//这里可以查看invoke中调用方法的名称
System.out.println("method name="+method.getName());
//该参数是一个数组类型Object[] arg2
for(int i=0;i<arg2.length;i++){
System.out.println(arg2[i]);
}
Object result=null;
//下面才是真正调用的方法,将对象添加到invoke 方法中
try{
result=method.invoke(object, arg2);
//方法执行之后,也可以自定义方法
}catch(Exception e){
e.printStackTrace();
}
return result;
}
public void checkSecurity(){
System.out.println("-----checkSecurity------");
}

}

下面我们来细细分析这个类,首先实现接口 invocationHandler ,还有方法 invoke(). 当代理类产生代理之后,在调用所有的方法之前都会先执行 invoke() 方法(想到 AOP 中的 BeforeAdvice 了吗?)。方法 checkSecurity() 就是我提到的验证方法,我们写在代理类中,而你在原先类中去看不到他的具体引用。其中 method.getName() 是获得所传入对象所调用的方法的方法名。 ( 假如你只需要对名称为 addUser 的方法进行单独验证,加个条件判断不就可以了麽,有点 Spring 的味道了吗? ) 再看, method.invoke() 这才是真正调用的方法,在到这一步之前我已经添加了许多验证方法了,而这在原先类中却什么都看不到一切我们都在代理类中实现的。这就避免了对原先类的修改了。当然这个方法调用之后,你还可以继续添加方法(想到了 AOP 的 afteradvice 通知了吗?)
当你所需要的方法不断增多是你不是可以写成 xml 文件么,通过 xml 文件来配置方法。 Spring 大致就是从这个思想演变过来的。
最后看客户端:

Java代码



package com.jummy.spring;

public class Client {

public static void main(String args[]){

SecurityHandler handler=new SecurityHandler();

UserManager userManager=(UserManager)handler.newProxy(new UsreManagerImpl());

userManager.addUser(19861018, "Jummy");

}

}
package com.jummy.spring;

public class Client {
public static void main(String args[]){
SecurityHandler handler=new SecurityHandler();
UserManager userManager=(UserManager)handler.newProxy(new UsreManagerImpl());
userManager.addUser(19861018, "Jummy");
}
}

通过代类理的实例来代理原先类( newProxy(new UserManagerImple()) ) . 然后你再去调用 addUser() 方法。所有的验证都添加进去了。

可能讲了半天有的朋友还只是说没有 AOP ,其实要讲 AOP 不一定要把 AOP 啃个遍,关键是要理解如何实现 AOP 如何区别于 OOP 的纵向编程。当然, OO 起家的我觉得 AOP 始终是个补充,万事无绝对。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: