使用proxy实现日志打印

作者: 司鑫 | 来源:发表于2016-12-18 14:05 被阅读62次

    1 代理模式简介


    代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    代理导图

    2 应用场景


    假如有一组对象同时实现了一个接口并实现了接口中所有的方法,现在我们要在这组对象中的部分对象加上单独的方法,传统的方法就只能在每个对象中去编写一个方法,这样会导致代码的重用性低,耦合度高。

    现在我们就用代理的方法来实现简单日志打印的效果

    3 简单日志打印的效果


    目的:在方法执行前打印 “系统时间+执行的方法名” ,在方法执行后打印“方法执行完毕”

    3.1 创建接口及其实现类

    接口:IUserDao.class

    public interface IUserDao {
        
        void doBreakfast();     
        void doLunch();
    }
    

    接口实现:UserDao.class

    public class UserDao implements IUserDao{
    
        @Override
        public void doBreakfast() {
            System.out.println("开始吃早餐");
        }
    
        @Override
        public void doLunch() {
            System.out.println("开始吃午餐");
        }
    
    
    }
    
    3.2 编写自定义的代理类

    代理类 :LogProxy.class

    <!--自定义的代理类需要实现 InvocationHandler类并实现invoke方法--!>
    public class LogProxy implements InvocationHandler{
        private Object target;//要代理的对象信息
        public Object bind(Object targer){
            this.target = targer;
            return Proxy.newProxyInstance(//创建一个代理对象
                    targer.getClass().getClassLoader(), //获取需要代理对象的类加载器
                    targer.getClass().getInterfaces(),//获取需要代理对象的所有接口
                    this);//返回当前代理对象
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            this.log(method.getName());
                    <!-可以对代理对象中的方法进行过滤处理,比如:对特定的方法才进行打印-!>
                      <!- ........  -!>
            Object obj = method.invoke(this.target, args);//执行代理对象中的方法
            this.finish(method.getName());
                
            return obj;
        }
    
        public void log(String name){
            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                  .format(new Date())+";执行方法:"+name);
        }
        public void finish(String name){
            System.out.println(name+"执行完毕");
        }
    }
    
    3.3 创建Demo测试小效果

    ProxyDemo.class

    public class ProxyDemo {
        public static void main(String[] args) {
            IUserDao bind = (IUserDao) new LogProxy().bind(new UserDao());
            bind.doBreakfast();
        }
    }
    
    效果图

    4 缺陷及改进方法


    相对于传统的方法,使用代理的方法效率明显提高,耦合性也大大降低,但还是存在一些缺陷,比如:在我们对一个对象进行代理时,该类必须要实现一个及以上的接口,否则将会报错。如下图

    java.lang.ClassCastException

    最后的解决方法我们采用Cglib实现代理。

    5 Cglib处理代理


    5.1 导入cglib包(www.sf.net)
    5.2 对应的类解释
    • net.sf.cglib.proxy.Enhancer:相当于Proxy类的功能,返回代理对象
    • net.sf.cglib.proxy.MethodInterceptor:是一个处理代理操作的接口
    • net.sf.cglib.proxy.MethodProxy:代替之前的Method类的功能。
    5.3 代理类实现

    CglibProxyDemo.class

    class CglibProxyDemo{
        public static void main(String[] args) {
            UserDao userdao = new UserDao();
            Enhancer  en = new EnHance();//代理类对象
            en.setSuperclass(UserDao.class);//为代理类设置一个父类
            en.setCallback(new MethodInterceptor(){
                
                @Override
                public Object intercept(Object obj, Method method, Object[] args,
                        MethodProxy proxy) throws Throwable{
                    System.out.println("打印日志");
                    return method.invoke(obj,args);
                }
            });
            UserDao dao = (UserDao)en.create();//返回代理对象
            dao.doBreakfast();
        }
    }
    

    相关文章

      网友评论

        本文标题:使用proxy实现日志打印

        本文链接:https://www.haomeiwen.com/subject/ppwamttx.html