spring中AOP动态代理基本原理
2012-11-20 14:42:06| 分类: spring|字号 订阅
spring的AOP中,代理技术是重要的部分,spring的AOP默认采用了动态代理机制。下面模拟一下动态代理机制的实训
假设有个接口UserDAO:
package com.gdsyhgxy.dao;
import com.gdsyhgxy.model.User;
public interface UserDAO {
public void add(User u);
public void delete(int id);
}
实现UserDAO的UserDAOImpl
package com.gdsyhgxy.dao.impl;
import com.gdsyhgxy.dao.UserDAO;
import com.gdsyhgxy.model.User;
public class UserDAOImpl implements UserDAO {
public void add(User u) {
// TODO Auto-generated method stub
System.out.println(“a user save”);
}
public void delete(int id) {
// TODO Auto-generated method stub
System.out.println(“a user delete”);
}
}
那么如果现在有这样一个业务逻辑,就是在add(User u)执行前加点业务逻辑,在其执行之后加点业务逻辑,这时就像再原来添加用户的业务逻辑上加上了横向的条件进去,这就是所谓的面向切面的编程思想,类似此种情况,使用动态代理尤为适合。
那么怎么样产生一个动态代理类呢,要用到JDK里面的Proxy类和InvocationHandler类
Proxy中的newProxyInstance(ClassLoader loader;Class<?>[] Interfaces,InvocationHandler h)可以用来产生动态代理
ClassLoader loader是类加载器
Class<?>[] Interfaces是被代理类实现的接口
InvocationHandler h;InvocationHandler接口的之类的实例;
InvocationHandler类中invoke(Object proxy,Method m,Object[] args);
Object proxy:被代理对象,
Method m:被调用的方法;
Object[] args:被调用方法的参数;
下面是实现动态代理类的代码
package com.gdsyhgxy.dao.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserDAOImplInvcationHandler implements InvocationHandler {
//声明被代理对象;
private Object targetObject;
//通过被代理对象得到代理对象
public Object newProxy(Object targetObject){
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeMethod(method);
method.invoke(targetObject,args);
behindMethod(method);
return null;
}
//在方法执行前加的业务逻辑
private void beforeMethod(Method method){
System.out.println(method.getName()+” start”);
}
//在方法执行后加的业务逻辑
private void behindMethod(Method method){
System.out.println(method.getName()+” end”);
}
}
方便起见,这里在方法前后加的业务逻辑都简单的写成一个打印语句,
在主函数中测试:
UserDAO dao = new UserDAOImpl();
UserDAOImplInvcationHandler handler = new UserDAOImplInvcationHandler();
UserDAO userDAO = (UserDAO)handler.newProxy(dao);
userDAO.delete(1);
控制台打印出:
delete start
a user delete
delete end
这时我们会想为什么调用的是userDAO的delete方法,怎么前面后面就都加上了业务逻辑了呢?注意:UserDAO是这样子产生的
UserDAO userDAO = (UserDAO)handler.newProxy(dao);也就是UserDAO实际上已经是个代理对象了,因为在创建代理对象的时候用到Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);,传进去的有被代理对象的类加载器,被代理对象实现的接口,和InvocationHandler接口的之类的实例,可以知道,代理对象也将实现被代理对象实现过的接口,其也拥接口中定义的方法,但是在代理中是怎么调用其里面的方法使得方法前后都加上所需的业务逻辑的。
大概如下
class $Proxy4 implement UserDAO{
public void save(User u){
Method m = UserDAO.getClass.getMethod(“save”) ;
handler .invoke(this,m,u);
}
}
这个解释是基于上面程序说明的,这里的handler 指的是前面程序写的UserDAOImplInvcationHandler handler = new UserDAOImplInvcationHandler();中的handler ;
由此我们就可以知道,代理里面在调用每个方法时都是去调用了实现动态代理类中的invoke的方法,所以我们只需要根据自己的需要在invoke方法里加入所需的业务逻辑既可。
这种动态代理的实现补充了传统面向对象编程的不足,代码耦合性大大降低,当要使用动态代理时我们将其加入,不用是很方便的就将其摘掉。
使用动态代理可以做如验证权限,方法效率测试,日记记录等等