静态代理:
先画一个静态代理的类图。
从上图我们可以看出,静态代理主要有3个部分实现。
首先,需要一个接口,这个接口拥有一个代理类与被代理类的共有的一个方法。然后需要一个被代理类,实现定义的接口。再定义一个代理类,实现接口并且依赖被代理的对象。这样一个静态代理的过程就实现了。当客户端调用的时候,调用的就是代理类的实例,调用的方法就是被代理类实例增强后的被代理类的方法。
SellCar接口:
public interface SellCar {//代理类与被代理类共同实现的接口
void sellCar();
}
CarFactory被代理类:
public class CarFactory implements SellCar{
@Override
public void sellCar() {
System.out.println("汽车生产商:组装车辆,并出售...");
}
}
ProxyStore代理类:
public class ProxyStore implements SellCar{
private CarFactory carFactory;//依赖一个被代理类的对象
public ProxyStore(CarFactory carFactory){
this.carFactory = carFactory;
}
@Override
public void sellCar() {//对被代理类的方法进行增强
System.out.println("代理商:向汽车工厂购买车辆...");
carFactory.sellCar();
System.out.println("代理商:代理销售汽车...");
}
}
Custom客户端:
public class Custom {
public static void main(String[] args) {
ProxyStore proxyStore = new ProxyStore(new CarFactory());
proxyStore.sellCar();
}
}
动态代理:
通过上面的静态代理,虽然我们实现了对被代理类功能的增强,但是我们也可以很清晰的发现一个问题。所有的方法都已经写死在程序中了,当我们需要去增加或去修改方法时,对于程序的改动就会很大,这样就很容易出现问题。因此我们可以使用动态代理。动态代理分为2种:JDK代理和CGLIB代理。
JDK代理:
JDK的实现原理:
在JDK代理中,不需要代理类再去实现与被代理对象共有的接口方法。代理类依赖于JDK提供的Proxy类,使用该类中的newProxyInstance方法通过反射可以得到一个代理类的实例对象。代理类还需要实现InvocationHandler接口总的invoke方法,通过反射得到被代理对象的方法的具体信息对象,然后在invoke方法中对其进行增强。
JDK的实现:
SellCar接口:
public interface SellCar {//代理类与被代理类共同实现的接口
void sellCar();
}
CarFactory被代理类:
public class CarFactory implements SellCar{
@Override
public void sellCar() {
System.out.println("制造商:制造车辆...");
System.out.println("制造商:出售车辆...");
}
}
}
ProxyStore代理类:
public class ProxyStore {
private CarFactory carFactory;
public ProxyStore(CarFactory carFactory){
this.carFactory = carFactory;
}
/**
* @return 代理类的实例对象
*/
public Object getProxyInstance(){
/**
* arg1:被代理类的类加载器,获取被代理类的具体信息
* arg2:获取被代理类的所有接口
* arg3:匿名内部类实现了InvocationHandler接口,返回的是被代理的方法执行后的返回值
*/
return Proxy.newProxyInstance(carFactory.getClass().getClassLoader(), carFactory.getClass().getInterfaces(),
new InvocationHandler() {
@Override
/**
* arg1:生成的被代理类的代理类的实例对象
* arg2:代理类的实例对象执行的方法,是对被代理类目标方法的增强
* arg3:代理类的实例对象执行的方法的参数列表
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理商:向制造商购买汽车...");
Object invoke = method.invoke(carFactory, args);
System.out.println("代理商:代理出售...");
return invoke;
}
});
}
}
Custom客户端:
public class Custom {
public static void main(String[] args) {
ProxyStore proxyStore = new ProxyStore(new CarFactory());
SellCar proxy = (SellCar) proxyStore.getProxyInstance();//自动生成代理类的对象,实现了SellCar接口
proxy.sellCar();
}
}
CGLIB代理
通过上述的JDK代理实现的描述,我们不难发现。JDK代理是自动生成一个类实现了与代理目标类共同的接口,如果没有目标类的接口类,就不能够使用JDK代理。为了解决这种问题,提出了CGLIB代理。
CGLIB代理原理:
生成的代理类是被代理类的子类覆盖了父类的方法。通过多态的性质,当子类覆盖了父类的方法时,创建子类对象强转为父类对象后,调用父类对象的方法时优先调用子类覆盖父类的方法,实现对于目标方法的增强。
CGLIB代理的实现:
要实现CGLIB我们先需要导入CGLIB的jar包(这里使用IDEA直接导入依赖)
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
ProxyStore生成代理类:
public class ProxyStore implements MethodInterceptor {
Enhancer enhancer = new Enhancer();
/**
* @param clazz 被代理类的字节码文件
* @return 获取被代理类的一个代理对象
*/
public Object getProxyInstance(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* @param o 自动生成的被代理类的代理类的实例对象
* @param method 被代理类执行的方法
* @param objects 参数列表
* @param methodProxy 代理类执行的方法对象
* @return 被代理类的方法执行后的返回值
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理商:向汽车厂商购买车辆...");
Object invokeSuper = methodProxy.invokeSuper(o, objects);
System.out.println("代理商:代理出售...");
return invokeSuper;
}
}
CarFactory被代理类:
public class CarFactory{
public void sellCar() {
System.out.println("制造商:制造车辆...");
System.out.println("制造商:出售车辆...");
}
}
Custom客户端:
public class Custom {
public static void main(String[] args) {
ProxyStore proxyStore = new ProxyStore();
CarFactory proxy = (CarFactory) proxyStore.getProxyInstance(CarFactory.class);
proxy.sellCar();
}
}
CGLIB代理与JDK代理的区别:
JDK代理: 生成的代理类是实现了被代理类的接口。因此没有接口的被代理类不能使用JDK代理。
CGLIB代理: 生成的代理类继承了被代理类,是被代理类的子类。因此,被代理类不能被final修饰,需要被增强的方法也不能够被final修饰。