代理模式

1.正常接口实现

接口

public interface IUserDao {
    public void save();
}

实现接口

public class UserDao implements IUserDao{

    @Override
    public void save() {
        System.out.println("保存入数据库成功");
    }

}

调用使用

//正常情况
        IUserDao userDao=new UserDao();
        userDao.save();

结果:

保存入数据库成功;

2.静态代理模式

接口一样:

public interface IUserDao {
    public void save();
}

实现接口由代理类实现,初始化赋予权限,一样要实现接口

public class StaticProxy implements IUserDao{
    private IUserDao userDao;
    public StaticProxy(IUserDao userDao) {
        this.userDao=userDao;
    }
    @Override
    public void save() {
        System.out.println("事务开始");
        userDao.save();
        System.out.println("事务结束");
    }

}

同样是调用实现

IUserDao userDao=new UserDao();
//静态代理
        StaticProxy staticProxy=new StaticProxy(userDao);
        staticProxy.save();

结果:

事务开始
保存入数据库成功
事务结束

优点:可以对目标功能进行扩展,实现AOP切面编程,插入代码,不影响原有功能。

缺点:要是接口有很多方法,会导致代理类很多,万一接口有变动(比如更改一个返回类型int),对应方法的代理类就要维护更新。下面的动态代理就可以解决这个问题。

3、动态代理

利用反射机制,代理类所在包:java.lang.reflect.Proxy

核心方法

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

第一个参数为类加载器,第二个为实现方法的接口,第三个是代理类

同样,还是原来的接口

public interface IUserDao {
    public void save();
}

原来的接口实现类

public class UserDao implements IUserDao{

    @Override
    public void save() {
        System.out.println("保存入数据库成功");
    }

}

创建动态代理的类同时实现接口InvocationHandler,这个 是代理实例的调用处理程序 实现的接口,重写一下唯一的一个invoke方法。

public class UserProxy implements InvocationHandler{
    private IUserDao userDao;
    public UserProxy(IUserDao userDao) {
        this.userDao=userDao;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("动态代理");
        System.out.println("开始事务");
        Object invoke = method.invoke(userDao, args);
        System.out.println("结束事务");
        return invoke;
    }

}

测试:

public class Test {
    public static void main(String[] args) {
        IUserDao userDao=new UserDao();

        //代理情况(不用继承也可以调用接口的方法)
        ClassLoader classLoader = UserDao.class.getClassLoader();
        IUserDao Iproxy=(IUserDao) Proxy.newProxyInstance(classLoader, UserDao.class.getInterfaces(), new UserProxy(userDao));
        Iproxy.save();

    }
}

动态生成代理对象Iproxy,就可以调用相应的方法了。

结果:

动态代理
开始事务
保存入数据库成功
结束事务


 

如果改了接口返回类型为int,那么

接口:

public interface IUserDao {
    public int save();
}

接口实现类就这样:

public class UserDao implements IUserDao{
    @Override
    public int save() {
        System.out.println("保存入数据库成功");
        return 110;
    }

}

动态代理类不变

测试类:打印一下返回值

public class Test {
    public static void main(String[] args) {
        IUserDao userDao=new UserDao();
        //代理情况(不用继承也可以调用接口的方法)
        ClassLoader classLoader = UserDao.class.getClassLoader();
        IUserDao Iproxy=(IUserDao) Proxy.newProxyInstance(classLoader, UserDao.class.getInterfaces(), new UserProxy(userDao));
        int save = Iproxy.save();
        System.out.println(save);

    }
}

结果:多了个110

动态代理
开始事务
保存入数据库成功
结束事务
110

可以发现不用改动态代理的类,省事。当然,大部分情况我们都会对这些进行封装,使用就更简单了。

原文地址:https://www.cnblogs.com/lq625424841/p/7170775.html