spring两种代理方式
若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
今天咱们主要讨论JDK动态代理的方式。JDK的代理方式主要就是通过反射跟动态编译来实现的。
1.创建接口Animal.java
package cn.xxs.proxy;
/**
* 动物
* @author xxs
*
*/
public interface Animal {
/**
* 吃
*/
public void eat();
}
2.接口的实现Tiger.java
package cn.xxs.proxy.impl;
import cn.xxs.proxy.Animal;
/**
* Tiger
* @author xxs
*
*/
public class Tiger implements Animal{
@Override
public void eat() {
System.out.println("吃肉");
}
}
3.生成代理对象(proxy)
TigerProxy.java
在JDK动态代理中需要实现接口:java.lang.reflect.InvocationHandler.
首先声明一个类的属性target,它的作用是保存真实服务对象(B);然后用bind方法绑定代理对象(proxy商务)和真实对象(A)。
用之前的比喻就是proxy就是商务,它代理了target(A),而商务代理的逻辑方法放在this这个对象的invoke方法中,只是this这个对象需要实现InvocationHandler接口而已。这样,声明就会进入当前类的invoke方法中,它实现的是代理逻辑,它有三个参数
Object proxy——当前代理对象(商务)
Method method——当前调度的方法
Object[] args——方法参数
然后我们通过反射调度真实对象的方法,Object obj = method.invoke(target, args);//相当于eat方法调用,实现功能。
package cn.xxs.proxy.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TigerProxy implements InvocationHandler {
//定义目标对象,也就是被代理对象
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
/**
* 自定义一些逻辑
*/
public void logBegin() {
System.out.println("记录开始");
}
public void logAfter() {
System.out.println("记录结束");
}
/**
* proxy:被代理对象
* method:被代理对象中的方法名
* args:方法对应的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//记录动物准备开始吃了
logBegin();
//继续执行被代理对象的方法
Object obj = method.invoke(target, args);
//记录结束了
logAfter();
return obj;
}
}
4.打印测试ProxyTest.java
package cn.xxs.test;
import java.lang.reflect.Proxy;
import org.junit.Test;
import cn.xxs.proxy.Animal;
import cn.xxs.proxy.impl.Tiger;
import cn.xxs.proxy.impl.TigerProxy;
public class ProxyTest {
@Test
public void test() {
//创建代理对象
TigerProxy proxy = new TigerProxy();
//创建被代理对象
Animal animal = new Tiger();
//把被代理对象传到代理对象中,用于invoke
proxy.setTarget(animal);
//创建代理对象1.loader类加载器2.被代理对象实现的接口3.实现InvocationHandler类的实例对象
Animal tiger = (Animal) Proxy.newProxyInstance(animal.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);
//调用代理类中的方法
tiger.eat();
}
}
5.测试结果