开局附上高手链接
Jdk的动态代理,只能代理接口对象
原因是代理对象默认继承Proxy,然而Java语言特性只支持单继承,反编译可得如下代码
public final class UserDao$ProxyCode extends Proxy implements UserDao
- 1.InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。
/*参数:
proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 Method 实例。 Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
返回:
从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
-
2.Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。
/*参数: loader - 定义代理类的类加载器 interfaces - 代理类要实现的接口列表 h - 指派方法调用的调用处理程序 返回: 一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口*/ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
具体代码实现
public interface UserDao {//定义接口
void save();
void update();
void delete();
void find();
}
public class UserDaoImpl implements UserDao {//实现接口
@Override
public void save() {
System.out.println("save-------");
}
@Override
public void update() {
System.out.println("update------");
}
@Override
public void delete() {
System.out.println("delete------");
}
@Override
public void find() {
System.out.println("find--------");
}
}
//实现InvocationHandler接口的调用处理程序
//并封装一个获得代理对象的方法
public class MyJdkProxy implements InvocationHandler {
private UserDao userDao;
public MyJdkProxy(UserDao userDao){
this.userDao = userDao;
}
public Object createProxy(){
Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
this
);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("save".equals(method.getName())){
System.out.println("权限校验中......");
return method.invoke(userDao, args);
}
if("find".equals(method.getName())){
System.out.println("权限校验中......");
return method.invoke(userDao, args);
}
return method.invoke(userDao, args);
}
}
public class SpringDemo1 {
@Test
public void demo1(){
UserDao userDao = new UserDaoImpl();
// userDao.save();
// userDao.delete();
// userDao.update();
// userDao.find();
UserDao proxy = (UserDao) new MyJdkProxy(userDao).createProxy();
proxy.save();
proxy.find();
proxy.update();
proxy.delete();
}
}
Cglib动态代理
使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
代理对象默认实现Factory接口,Jdk允许实现多个接口
反编译获得代码
//实现接口方式
public class ProductDao?EnhancerByCGLIB?40fd3cad implements ProductDao, Factory{
//...
}
//实现类的方式
public class ProductDao$ProductDao?EnhancerByCGLIB?58419779 extends ProductDao implements Factory {
//...
}
- MethodInterceptor接口类似InvocationHandler
- Enhancer类似Proxy类
具体代码实现
public class ProductDao {
public void save() {
System.out.println("save product-------");
}
public void update() {
System.out.println("update product------");
}
public void delete() {
System.out.println("delete product------");
}
public void find() {
System.out.println("find product--------");
}
}
public class MyCglibProxy implements MethodInterceptor {
private ProductDao productDao;
public MyCglibProxy(ProductDao productDao){
this.productDao = productDao;
}
public Object createProxy(){
//1 创建核心类
Enhancer enhancer = new Enhancer();
//2 设置父类
enhancer.setSuperclass(productDao.getClass());
//3 设置回调
enhancer.setCallback(this);
//4 生成代理
Object proxy = enhancer.create();
return proxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if("save".equals(method.getName())){
System.out.println("权限校验中......");
return methodProxy.invokeSuper(proxy, args);
}
return methodProxy.invokeSuper(proxy, args);
}
}
public class SpringDemo2 {
@Test
public void demo1(){
ProductDao productDao = new ProductDao();
ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
// productDao.save();
// productDao.delete();
// productDao.find();
// productDao.update();
proxy.save();
proxy.find();
proxy.update();
proxy.delete();
}
}