代理代码实现

jdk动态代理

1、有个Person接口

package com.xiangwen.day5.jdk;

public interface Person {
    public void say(String str);
    public void listen(String str);
}

2、有个PersonImpl接口实现类

package com.xiangwen.day5.jdk;


public class PersonImpl implements Person {
    @Override
    public void say(String str) {
        System.out.println(str);
    }

    @Override
    public void listen(String str) {
        System.out.println(str);
    }
}

3、创建接口的代理类PersonProxy

package com.xiangwen.day5.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PersonProx implements InvocationHandler {
    private Person person;

    public PersonProx(Person person) {
        this.person = person;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object o=null;
        if("say".equals(method.getName())){
            System.out.println("111111111befre---------------");
             o=method.invoke(person,args);
            System.out.println("111111111end-----------------");
        }else if("listen".equals(method.getName())){
            System.out.println("222222222befre---------------");
            o=method.invoke(person,args);
            System.out.println("222222222end-----------------");
        }
        return o;
    }
}

4测试

package com.xiangwen.day5.jdk;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        Person person=new PersonImpl();
        InvocationHandler personProx=new PersonProx(person);
        Person p= (Person) Proxy.newProxyInstance(personProx.getClass().getClassLoader(),person.getClass().getInterfaces(),personProx);
        p.say("hello");
        System.out.println();
        p.listen("祝你平安!");
    }
}

 

结果截图:

 

 

 

 

 

cglib动态代理

maven依赖:

  <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.11</version>
        </dependency>
        <dependency>
            <groupId>org.objectweb.asm</groupId>
            <artifactId>com.springsource.org.objectweb.asm</artifactId>
            <version>3.1.0</version>
        </dependency>

1.有一个类PerosonImpl

package com.xiangwen.day5.cglib;

import com.xiangwen.day5.jdk.Person;

public class PersonImpl  {
    public void say(String str) {
        System.out.println("说:"+str);
    }
    public void listen(String str) {
        System.out.println("听:"+str);
    }
}

2、建一个代理类为方法1处理

package com.xiangwen.day5.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class PersonProx implements MethodInterceptor {
    @Override
    public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
        System.out.println("Before Method Invoke");
        proxy.invokeSuper(object, objects);
        System.out.println("After Method Invoke");
        return object;
    }
}

3、建第二个代理类为方法2处理

package com.xiangwen.day5.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class PersonProx2 implements MethodInterceptor {
    @Override
    public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
        System.out.println("PersonProx2====Before Method Invoke");
        proxy.invokeSuper(object, objects);
        System.out.println("PersonProx2====After Method Invoke");
        return object;
    }
}

4、建一个MyFilter方法与代理类的顺序

package com.xiangwen.day5.cglib;

import net.sf.cglib.proxy.CallbackFilter;

import java.lang.reflect.Method;

public class MyFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if("say".equals(method.getName())){
return 0;
}else if("listen".equals(method.getName())){
return 1;
}
return 1;//下标不能超过new Callback[]数组的下表,否则会报错
}
}

5、测试

@org.junit.Test
public void test2(){
    PersonProx personProxy = new PersonProx();
    PersonProx2 personProxy2 = new PersonProx2();
    MyFilter filter=new MyFilter();
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(PersonImpl.class);
    enhancer.setCallbacks(new Callback[]{personProxy,personProxy2});
    enhancer.setCallbackFilter(filter);
    PersonImpl person = (PersonImpl)enhancer.create();
    person.say("说你爱我");
    System.out.println();
    person.listen("听雨");
}

 

6、结果截图

 

 如果不单独指定代理,所有方法都用personProxy代理

   public static void main(String[] args) {
        PersonProx personProxy = new PersonProx();

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(PersonImpl.class);
        enhancer.setCallback(personProxy);
        PersonImpl person = (PersonImpl)enhancer.create();
        person.say("说你爱我");
        person.listen("听雨");
    }

 

区别:

jdk:利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,
在调用具体方法前调用InvokeHandler来处理。

JDK动态代理只能对实现了接口的类生成代理,而不能针对类。

cglib:利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,
并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,
对于final类或方法,是无法继承的。

 

什么情况使用:

1)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。

2)如果目标对象实现了接口,可以强制使用CGLIB实现AOP。

3)如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。

 

sping如何选择jdk和cglib
如果bean实现接口,默认使用jdk动态代理
如果bean没有实现接口,默认使用cglib动态代理
在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>强制使用cglib
 
哪个更快

1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在jdk6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

2)在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,总之,每一次jdk版本升级,jdk代理效率都得到提升,而CGLIB代理效率确有点跟不上步伐。



posted @ 2021-06-18 17:25  傲云萧雨  阅读(147)  评论(0编辑  收藏  举报