java框架基础(3)

代理

静态代理:

接口a定义了方法aa,实现了接口a的实现类b和实现类c;如何用c来代理b;

其实就是把b类实例化后作为参数通过c类的构造函数注入到c类中,这样就可以在c类里调用b类里自己重写的aa方法了;

JDK动态代理:

这里涉及两个类:Proxy类和InvocationHandler类;

Proxy类用得最多的就是newProxyInstance 这个方法:

 这个方法的作用就是得到一个动态的代理对象,其接收三个参数

loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

package com.lzj;

/**
 * @Description: TODO
 * @author: lzj
 * @date: 2021年04月27日 16:53
 */



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

/**
 * 动态代理举例
 *
 *
 * **/

interface Human{
    void getBelief();
    void eat(String food);
}
//被代理类
class SuperMan implements Human{

    @Override
    public void getBelief() {
        System.out.println("I believe I can fly!");
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃"+food);
    }
}


class ProxyFactory{
    //调用此方法,返回一个代理类的对象,解决了问题1
    public static Object getProxychInstance(Object obj){//obj:被代理类的对象
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }
}
class MyInvocationHandler implements InvocationHandler {
    private Object obj;
    public void bind (Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象,调用方法a,就会自动调用如下方法:invoke()
    //将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method:就是代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        if(method.getName().equals("eat")){
        System.out.println("before rent house");

        System.out.println("Method:" + method);

        // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(obj, args);

        //   在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("after rent house");}
        return null;

    }

}
public class proxy {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        Human proxyInstance = (Human) ProxyFactory.getProxychInstance(superMan);
        proxyInstance.getBelief();
        proxyInstance.eat("麻辣烫");

    }
}

运行结果:

before rent house
Method:public abstract void com.lzj.Human.eat(java.lang.String)
我喜欢吃麻辣烫
after rent house

定义好InvocationHandler,这里可以做各种自定义业务;之后生成代理类后便可调用所传入参数的接口interfaces里所有的实现方法了;

之所以需要传入类加载器,是因为在生成代理类的时候,其实内部的原理是通过反射,把我们传入接口里的所有方法都遍历出来,再根据我们自己写好的业务再次编译一个class文件,再通过类加载器加载生成代理类到内存里,这里就很好地反映动态这个词了

CGLIB动态代理:

 CGLIB动态代理其实和jdk动态代理很是相似,依旧是在程序运行时生成新的字节码文件,生成被代理类的子类作为代理类,在调用被代理类方法时进行拦截,从而执行我们拦截器里自定义的方法;

同样涉及两个主要类:MethodInterceptor(拦截器接口)、Enhancer(字节码加强器)

package com.lzj;

import org.springframework.cglib.proxy.*;

import java.lang.reflect.Method;
import java.util.Calendar;

/**
 * @Description: TODO
 * @author: lzj
 * @date: 2021年04月28日 9:32
 */
//目标类
class CglibDao {

    public CglibDao() {
        select();
    }

    public void update() {
        System.out.println("CglibDao.update()");
    }

    public void select() {
        System.out.println("CglibDao.select()");
    }

}
//拦截器1
class CglibDaoProxy implements MethodInterceptor {

    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before method invoke");
        methodProxy.invokeSuper(object, args);
        System.out.println("after method invoke");
        return object;
    }

}
//拦截器2

class CglibDaoTwoProxy implements MethodInterceptor {
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("startTime : " + Calendar.getInstance().getTimeInMillis());
        methodProxy.invokeSuper(object, args);
        System.out.println("endTime : " + Calendar.getInstance().getTimeInMillis());
        return object;
    }
}
//回调器

class CglibFilter implements CallbackFilter {
    public int accept(Method method) {
        if ("select".equals(method.getName())) {
            return 1;
        }
        return 0;
    }

}

public class cglib {
    public static void main(String[] args) {
        cglibTest2();
    }


    public static void cglibTest2() {
        CglibDaoTwoProxy twoProxy = new CglibDaoTwoProxy();
        CglibDaoProxy proxy = new CglibDaoProxy();

        CglibFilter filter = new CglibFilter();
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(CglibDao.class);
        //设置拦截器替代调用方法
        enhancer.setCallbacks(new Callback[]{proxy, twoProxy});
        //配置回调器,在配置多拦截器时才会用到,根据返回的int作为拦截器数组的下标,采用不同的拦截器
        enhancer.setCallbackFilter(filter);
        //生成代理类
        CglibDao dao = (CglibDao) enhancer.create();
        dao.update();
        dao.select();
    }

}

执行之后返回的结果:

startTime : 1619592608771
CglibDao.select()
endTime : 1619592608800
before method invoke
CglibDao.update()
after method invoke
startTime : 1619592608800
CglibDao.select()
endTime : 1619592608800

可以看到delect方法对应的是拦截器2;而update方法对应的是拦截器1;

JDK动态代理和cglib代理的区别:

  • cglib无需实现接口,达到代理类无侵入,但是被代理类不能是final,因为所创建的代理类其实是被代理类的子类;
  • 使用动态代理必须实现接口
原文地址:https://www.cnblogs.com/lzj-learn/p/14679774.html