可以简单的认为,动态代理就是实现在不修改源程序的基础上,对原有的类方法进行增强。
其有一点要求是:要实现动态代理的类,必须实现至少一个接口。否则需要CGLIB动态代理机制。
JDK的动态代理机制也是Spring AOP的底层实现方式的一种。我们来了解一下其机制:
实现:实际使用方式可能多种多样,我们就按自己的来。
如,下面有一个接口:UserDao
package com.imooc.aop.demo1;
public interface UserDao {
public void save();
public void update();
public void delete();
public void find();
}
其中有四个需要实现的方法。下面有一个实现类:UserDaoImpl
package com.imooc.aop.demo1;
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("保存用户...");
}
public void update() {
System.out.println("修改用户...");
}
public void delete() {
System.out.println("删除用户...");
}
public void find() {
System.out.println("查询用户...");
}
}
现在需要对save()方法进行权限的检查。使用动态代理方式。先编写一个工具类:MyJdkProxy。这个类的目的是用来生成动态代理对象,以及添加的业务逻辑,此处就是对save()方法进行权限检查。
package com.imooc.aop.demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//实现InvocationHandler接口,实现其中的invoke()方法
public class MyJdkProxy implements InvocationHandler {
//这里使用一个目标接口对象为属性,以方便获得其类加载器
private UserDao userDao;
//构造方法中传入一个目标类,赋值给属性
public MyJdkProxy(UserDao userDao){
this.userDao = userDao;
}
//获取代理对象的方法
public Object createProxy(){
//获得代理对象。使用Proxy的静态方法:newProxyInstance(目标类加载器,目标类的接口,InvocationHandler的实现类)
Object proxy = Proxy.newProxyInstance(
userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
return proxy;
}
//实现InvocationHandler的invoke(代理对象,目标方法,目标方法参数)。执行代理对象方法时,就是执行此invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//因为仅对save方法进行修改,此处进行判断,进行业务的处理。
if("save".equals(method.getName())){
System.out.println("权限校验=========");
}
//返回method的invoke方法。在java反射中提到过,方法对象最重要的方法就是invoke。该方法返回Object对象
//反射机制使用此方法:invoke(方法调用对象,方法参数)来执行方法对象所对应的方法
return method.invoke(userDao,args);
}
}
以上程序实现了生成代理对象以及对save()方法进行处理。下面测试一下:
package com.imooc.aop.demo1;
import org.junit.Test;
public class SpringDemo1 {
@Test
public void demo1(){
UserDao userDao = new UserDaoImpl();
UserDao proxy = (UserDao)new MyJdkProxy(userDao).createProxy();
proxy.save();
proxy.delete();
proxy.find();
proxy.update();
}
}
在输出结果可以看到,执行save()方法时进行了校验。
需要说明的时,使用spring时,我们通常不会写以上这些代码,spring已经封装好了动态代理机制。我们只需要修改配置文件即可。