从来就没有救世主  也不靠神仙皇帝  要创造人类的幸福  全靠我们自己  

java---代理模式

 

代理:在不修改目标对象的功能的前提下,通过代理对目标对象进行功能扩展

 1. 静态代理

静态代理:

  例子:

public interface UserDao{
    void save();
}

 

public class UserDaoImpl implements UserDao {
    @Override
    public void save(){
        System.out.println("保存数据");
    }
}

  

  以上,UserImpl的方法save(),如果需要在操作之前开启事务、操作完后提交事务,则要这么写:

public class UserDaoImpl implements UserDao {
    @Override
    public void save(){
        fun_session();
        System.out.println("保存数据");
        fun_commit();
    }
}

 

  如果类中有很多方法,都需要操作之前开启事务,操作完后提交事务,则造成了 开启事务、提交事务 这部分冗余重复。我们抛弃掉上面这个写法,不修改UserDaoImpl,把额外的工作交给代理来实现,但是工作即save() 还是UserDaoImpl的对象来做的。

  代理类:

public class UserDaoProxy implements UserDao {
    private UserDao dao;
    public UserDaoProxy(final UserDao dao) {
        this.dao = dao;
    }
    
    @Override
    public void save() {
        fun_session();
        dao.save();
        fun_commit();
    }
}

  使用者:

UserDao dao = new UserDaoImpl();        //工作还是需要UserDaoImpl来做,需要这个对象
UserDao proxy = new UserDaoProxy(dao);  //创建代理对象
proxy.save();

 

  开启事务、提交事务的代码写在代理类里面

  静态代理的问题:

    如果接口改了,则代理也要改

    代理需要实现接口,则有很多接口时,也会有相应很多代理类

 


2. 动态代理

2.1动态代理1:基于接口的

    代理对象的产生时动态地在内存中构建,jdk中提供了相应的类

  java.lang.reflect.Proxy

  方法:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interface,reflect.InvocationHandler h)

       参数loader:目标对象类加载器

    参数interface:目标对象实现的接口类型

    参数h:指定的动态处理器,执行目标对象的方法时,会触发事件处理器的方法

 

  例子:

  接口:

public interface Person {
    void fun();
}

  实现类:

public class XT implements Person{
    @Override
    public void fun() {
        System.out.println("自己做了一些事情");
    }
}

 

  代理:

public class TestProxy {
    XT x = new XT();

    public Person getPersonProxy() {
        return (Person) Proxy.newProxyInstance(TestProxy.class.getClassLoader(), x.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if(method.getName().equals("fun")) {
                    System.out.println("代理做了一些事情");
                    method.invoke(x,args);
                }
                return null;
            }
        });
    }
}

 

  使用:

TestProxy a = new TestProxy();
Person proxy = a.getPersonProxy();
proxy.fun();

 

换个写法:

//接口
public interface HelloService {
    public void say();
}

//实现类
public class HelloServiceImpl implements HelloService {
    @Override
    public void say() {
        System.out.println("hello service");
    }
}

//需要我们写的代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("记录日志");
        Object invoke = method.invoke(target, args);
        System.out.println("清理数据");
        return invoke;
    }

    public Object getProxy(){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
    }
}
HelloService service = new HelloServiceImpl();
MyInvocationHandler handler = new MyInvocationHandler(service);
HelloService proxy = (HelloService) handler.getProxy();
proxy.say();    

 

 

 

2.2 动态代理2:CGLIB代理

  前面的动态代理需要目标类有实现的接口,不然Proxy.newProxyInstace的第二个参数缺少

  CGLIB使用了很底层的字节码技术,为一个类创建子类,并在子类中采用方法拦截的技术去拦截父类方法的调用。

  不能对final类代理(final类不能被继承)

  目标对象的 final、static方法不会被拦截

jar包:https://mvnrepository.com/artifact/cglib/cglib-nodep/3.3.0

package src.basegrammer.proxyTest;

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

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class clazz) {
        //设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("记录日志");
        //代理类调用父类方法
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("清理数据");
        return result;
    }
}

 

public void cglibTest(){
    CglibProxy proxy = new CglibProxy();
    //通过生成子类的方式创建代理类
    HelloServiceImpl proxyImp = (HelloServiceImpl) proxy.getProxy(HelloServiceImpl.class);
    proxyImp.say();
}

 

posted @ 2020-11-24 16:36  T,X  阅读(96)  评论(0)    收藏  举报