静态代理和动态代理原理及实现

一,静态代理

静态代理要先抽象出一个接口,并且写一个实现类实现这个接口。

//主业务接口
public interface SomeService {
String first();
String second();
}
//目标类
public class SomeServiceImpl implements SomeService{

	public String first() {
		// TODO Auto-generated method stub
		return "I Love You";
	}

	public String second() {
		// TODO Auto-generated method stub
		return "China";
	}

}

然后写静态代理类,要求静态代理类要求目标类共同实现主业务接口 。这里的代理类实现的是把目标类的某些方法的返回值变成大写。

public class SomeServiceProxy implements SomeService{
	private SomeService target;
	//提供无参构造器和带参构造器传递方法
	public SomeServiceProxy(){
		super();
	}
	public SomeServiceProxy(SomeService target) {
		super();
		this.target = target;
	}
	public String first() {
		// TODO Auto-generated method stub
		return target.first();//正常输出
	}
	public String second() {
		// TODO Auto-generated method stub
		return target.second().toUpperCase();//变大写
	}
}

写一个测试类

public class MyTest {
public static void main(String args[]){
	//定义目标对象
	SomeService target=new SomeServiceImpl();
	//定义目标对象的代理对象,把目标对象传进去
	SomeService serviceProxy=new SomeServiceProxy(target);
	String result1=serviceProxy.first();
	String result2=serviceProxy.second();
	System.out.println(result1+","+result2);
}
}

执行结果
在这里插入图片描述
执行了代理类之后,second方法的返回值变成了大写。

二,jdk动态代理

首先jdk动态代理和静态代理一样,都需要先抽象出来一个接口并实现这个接口。

//主业务接口
public interface SomeService {
String first();
String second();
}
//目标类
public class SomeServiceImpl implements SomeService{
	public String first() {
		// TODO Auto-generated method stub
		return "I Love You";
	}
	public String second() {
		// TODO Auto-generated method stub
		return "China";
	}
}

然后写测试类,动态代理在测试类中创建(Proxy类的newProxyInstance方法)

public class MyTest {
public static void main(String args[]){
	//定义目标对象
	final SomeService target=new SomeServiceImpl();
	//定义目标对象的代理对象
	SomeService serviceProxy=(SomeService)Proxy.newProxyInstance(
			target.getClass().getClassLoader(),//第一个参数:目标类的类加载器
			target.getClass().getInterfaces(),//第二个参数:目标类所实现的所有接口
			new InvocationHandler() {		//第三个参数:内部匿名类
				/**
				 * 增强就在这里完成
				 * proxy:代理对象
				 * method:目标方法
				 * args:目标方法的参数列表
				 */
				public Object invoke(Object proxy, Method method, Object[] args)
						throws Throwable {
					// 内部类使用外部类的成员变量,外部类的成员变量必须声明为final类型,否则报错
					Object result = method.invoke(target, args);
					//指定操作的是哪个方法
					if ("second".equals(method.getName())) {
						result = ((String) result).toUpperCase();
					}
					return result;
				}
			});
	String result1=serviceProxy.first();
	String result2=serviceProxy.second();
	System.out.println(result1+","+result2);
}
}

执行结果
在这里插入图片描述
second方法的返回值也变成了大写。

1,JDK动态代理小例子

一个小汽车,有一个跑run()的方法,我们想使用jdk动态代理使小汽车执行run之前 加点油,run之后洗车。有四个类,接口Car(小汽车)Kayan(具体实现类(卡宴)) CarProxy(汽车的代理) Test(测试类)

Car

public interface Car {
    public void run();
 }

Kayan这个是小汽车实现类

public class Kayan implements Car {
    @Override
    public void run() {
        System.out.println("小汽车开始跑。。。。。。。。");
    }
}

CarProxy 小汽车的代理类

public class CarProxy implements InvocationHandler {
    // 小汽车会被代理
    private Car car;
    // 通过set传入小汽车
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }

    public Car creatCarProxy() {
        Car proxy = (Car) Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), this);
        return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("run".equals(method.getName())) {
            // 小汽车想要跑之前那要先加油啊
            System.out.println("给小汽车加油啊。。oil。。oil。。oil");
            Object object = method.invoke(car, args);
            System.out.println("跑完之后给小汽车擦车啊。。clean。。clean");
            return object;
        }
        return method.invoke(car, args);
    }
}

测试代码

	// 测试小汽车的代理
    @Test
    public void testCarProxy() {
        Car ky = new Kayan();
        CarProxy proxy = new CarProxy();
        proxy.setCar(ky);
        Car carProxy = proxy.creatCarProxy();
        carProxy.run();
    }

最后的结果显示

这种实现的思想类似于Spring的Aop的实现思路,但是AOP在使用jdk动态代理的时候也是用CGLib代理 。

三,CGLIB动态代理

使用JDK的Proxy实现代理,要求目标类和代理类实现相同的接口,若目标类不存在接口,则无法使用该方式实现。对于无接口的类,要为其创建动态代理,就要使用CGLIB实现。CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。
所以,使用CGLIB动态代理,要求目标类必须能够被继承,即不能是final的类。

CGLIB是一个外部项目,首先要导入jar包
在这里插入图片描述

这里不需要抽象一个接口,只写一个主业务类。

//主业务类
public class SomeService {
	public String first() {
		// TODO Auto-generated method stub
		return "I Love You";
	}

	public String second() {
		// TODO Auto-generated method stub
		return "China";
	}
}

然后写一个CGLIB动态代理创建工厂

//要实现MethodInterceptor方法,返回的类型是回调函数,所以cglib_ProxyFactory 类本身也为回调函数对象
public class cglib_ProxyFactory implements MethodInterceptor{
	private SomeService target;
	public cglib_ProxyFactory() {
		super();
		// TODO Auto-generated constructor stub
	}
	public cglib_ProxyFactory(SomeService target) {
		super();
		this.target = target;
	}
	//用于创建cglib代理对象
	public SomeService myProxyCreator(){
		//增强器
		Enhancer enhancer=new Enhancer();
		//指定父类,即要增强的目标类
		enhancer.setSuperclass(SomeService.class);
		//指定回调函数对象
		enhancer.setCallback(this);
		//创建cglib代理对象
		return (SomeService) enhancer.create();
	}
public Object intercept(Object obj, Method method, Object[] args,
		MethodProxy proxy) throws Throwable {
	Object result = method.invoke(target, args);
	if ("second".equals(method.getName())) {
		result = ((String) result).toUpperCase();
	}
	return result;
}
}

再写一个测试类

public class MyTest {
public static void main(String args[]){
	//定义目标对象
	final SomeService target=new SomeService();
	//定义目标对象的代理对象
	SomeService serviceProxy=new cglib_ProxyFactory(target).myProxyCreator();
	String result1=serviceProxy.first();
	String result2=serviceProxy.second();
	System.out.println(result1+","+result2);
}
}

执行结果
在这里插入图片描述
second方法的返回值也变成了大写。

posted @ 2020-03-08 16:50  你樊不樊  阅读(161)  评论(0编辑  收藏  举报