静态代理和动态代理原理及实现
Posted fantongxue
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了静态代理和动态代理原理及实现相关的知识,希望对你有一定的参考价值。
@(静态代理(Static Proxy)和动态代理(Dynamic Proxy))
静态代理
静态代理要先抽象出一个接口,并且写一个实现类实现这个接口。
//主业务接口
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方法的返回值也变成了大写。
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方法的返回值也变成了大写。
以上是关于静态代理和动态代理原理及实现的主要内容,如果未能解决你的问题,请参考以下文章