java设计模式之代理模式举例

如:有一个添加用户的方法:add(),在添加之前和添加之后要做分别做两中日志记录。
1.静态代理:
    1-1.继承的写法:

//接口:
package com.watermelon.statics.proxy;

public interface UserService {
    public void add();
}
//添加用户的实现类
package com.watermelon.statics.proxy;

public class UserServiceImpl implements UserService{

    @Override
    public void add() {
        System.out.println("新增add");
    }

}
//代理类
package com.watermelon.statics.proxy;

public class UserServiceProxy extends UserServiceImpl{

    @Override
    public void add() {
        System.out.println("add 之前日志2");
        System.out.println("add 之前日志1");
        super.add();
        System.out.println("add 之后日志1");
        System.out.println("add 之后日志2");
    }

}
//测试方法
package com.watermelon.statics.proxy;

public class Main {

    public static void main(String[] args) {
        UserService userServiceProxy = new UserServiceProxy();
        userServiceProxy.add();
    }

}
//测试结果
//add 之前日志2
//add 之前日志1
//新增add
//add 之后日志1
//add 之后日志2

缺点:不够灵活,1.每次增加日志需修改代理类。2.若其他方法下需要同样的日志记录,则需要新增代理类。

    2-2.聚合的方式:类内部有其他类的变量。

//接口
package com.watermelon.statics.proxy;

public interface UserService {
    public void add();
}
//实现类
package com.watermelon.statics.proxy;

public class UserServiceImpl implements UserService{

    @Override
    public void add() {
        System.out.println("新增add");
    }
}
//代理类1:日志1
package com.watermelon.statics.proxy;

public class UserServiceProxy2 implements UserService{

    private UserService tagert;

    public UserServiceProxy2(UserService tagert) {
        super();
        this.tagert = tagert;
    }

    @Override
    public void add() {
        System.out.println("add 之前日志1");
        tagert.add();
        System.out.println("add 之后日志1");
    }
}
//代理类2:日志2
package com.watermelon.statics.proxy;

public class UserServiceProxy3 implements UserService{

    private UserService tagert;

    public UserServiceProxy3(UserService tagert) {
        super();
        this.tagert = tagert;
    }

    @Override
    public void add() {
        System.out.println("add 之前日志2");
        tagert.add();
        System.out.println("add 之后日志2");
    }
}
//测试类
package com.watermelon.statics.proxy;

public class Main {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserServiceProxy2 userServiceProxy = new UserServiceProxy2(userService);
        UserServiceProxy3 userServiceProxy3= new UserServiceProxy3(userServiceProxy);
        userServiceProxy3.add();
    }

}

测试结果同上。
和继承的方式比:新增日志记录不用修改代理类源码,直接新增代理类。
缺点:若要给其他的方法新增日志记录,则还是需要新增更多的代理类。

2.jdk动态代理。

//接口
package com.watermelon.de.proxy;

public interface UserService {
    public void add();
}
//实现类
package com.watermelon.de.proxy;

public class UserServiceImpl implements UserService{

    @Override
    public void add() {
        System.out.println("新增add");
    }
}
//代理工厂类 生成代理类 生成日志记录2代理类
package com.watermelon.de.proxy;

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

public class UserServiceProxyFactory1 implements InvocationHandler{

    private Object tagert;

    public MyTwoInvocationHandeler(Object tagert) {
        super();
        this.tagert = tagert;
    }

    public Object getProxy(){
        ClassLoader loader = tagert.getClass().getClassLoader();
        Class<?>[] interfaces = tagert.getClass().getInterfaces();
        return Proxy.newProxyInstance(loader, interfaces, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("之前日志2");
        Object result = method.invoke(tagert, args);
        System.out.println("之后日志2");
        return result;
    }

}
//代理工厂类 生成代理类 生成日志记录2代理类
package com.watermelon.de.proxy;

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

public class UserServiceProxyFactory2 implements InvocationHandler{

    private Object tagert;

    public MyTwoInvocationHandeler(Object tagert) {
        super();
        this.tagert = tagert;
    }

    public Object getProxy(){
        ClassLoader loader = tagert.getClass().getClassLoader();
        Class<?>[] interfaces = tagert.getClass().getInterfaces();
        return Proxy.newProxyInstance(loader, interfaces, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("之前日志2");
        Object result = method.invoke(tagert, args);
        System.out.println("之后日志2");
        return result;
    }

}
//测试类User类
package com.watermelon.de.proxy;

public class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        //UserServiceProxyFactory1  代理工厂类
        UserServiceProxyFactory1  proxyFactory1 = new UserServiceProxyFactory1 (userService);
        UserService userServiceproxy = (UserService) proxyFactory1.getProxy();
        UserServiceProxyFactory2  proxyFactory2 = new UserServiceProxyFactory2(userServiceproxy);
        UserService userServiceProxy1 = (UserService) proxyFactory2.getProxy();

        userServiceProxy1.add();
    }
}
//测试结果
之前日志2
之前日志1
新增add
之后日志1
之后日志2

在比如,我现在有个部门类有个update方法也要添加同样的两种日志记录

//部门接口
package com.watermelon.de.proxy;

public interface DepartmentService {

    public int update();

}
//实现类
package com.watermelon.de.proxy;

public class DepartmentServiceImpl implements DepartmentService{

    @Override
    public int update() {
        System.out.println("修改 update");
        return 1;
    }

}
//测试类
package com.watermelon.de.proxy;

public class Main {
    public static void main(String[] args) {


        DepartmentService departmentService = new DepartmentServiceImpl();
        UserServiceProxyFactory1  proxyFactory1 = new UserServiceProxyFactory1 (departmentService);
        DepartmentService departmentServiceProxy1 = (DepartmentService) proxyFactory1.getProxy();
        UserServiceProxyFactory2  proxyFactory2 = new UserServiceProxyFactory2 (departmentServiceProxy1);
        DepartmentService departmentServiceProxy2 = (DepartmentService) proxyFactory2.getProxy();
        departmentServiceProxy2.update();

    }
}

结论:使用动态代理每种日志记录可以灵活配置,分开添加。没新增一种日志记录,只需要新增一种代理类的生成类。
    生成动态代理类的步骤:
        1.添加InvocationHandler接口。实现重写public Object invoke(Object proxy, Method method, Object[] args)方法。
            2.添加一个private Object tagert;变量、并重写带tagert变量的构造方法。
        3.新增一个返回代理类的方法;通过Proxy.newProxyInstance(loader, interfaces, this);方法返回代理类。

4.cglib动态代理
不用和jdk动态地理一样需要实现同样的接口。直接生成类的动态代理类。

package com.watermelon.cglibproxy;

public class UserServiceImpl {
    public void add()
    {
        System.out.println("add loading...");
    }
}

CglibFactory 代理工厂类

package com.watermelon.cglibproxy;

import java.lang.reflect.Method;

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

public class CglibFactory implements MethodInterceptor{

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz){
        //设置创建子类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);

        return enhancer.create();
    }

    /**
     * 拦截所有目标类方法的调用
     * obj  目标类的实例
     * m   目标方法的反射对象
     * args  方法的参数
     * proxy代理类的实例
     */
    @Override
    public Object intercept(Object obj, Method m, Object[] args,
            MethodProxy proxy) throws Throwable {
        System.out.println("日志开始...");
        //代理类调用父类的方法
        proxy.invokeSuper(obj, args);
        System.out.println("日志结束...");
        return null;
    }

}

测试方法:

public static void main(String[] args) {
    UserServiceImpl userServiceImpl=  new UserServiceImpl();
        CglibFactory cglibFactory = new CglibFactory();
    UserServiceImpl userServiceImplProxy = (UserServiceImpl)cglibFactory.getProxy(userServiceImpl.getClass());
        userServiceImplProxy.add();
}

需要引入cglib-nodep-2.2.jar

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值