zoukankan      html  css  js  c++  java
  • 尚学堂Spring视频教程(五):Spring AOP

      在第一节中,我们自己模拟了一个Spring,实现一个保存用户的操作,假如现在有一个需求,在保存的时候记录日志,该怎么做呢?  

      暂且将记录日志操作就简单的变为在保存用户前输出一句话“save start...”,不建议直接在UserDAOImpl的save方法里写代码,因为我们有时候可能得不到源码,这个时候可以添加一个UserDAOImpl2继承UserDAOImpl,然后调用父类的save方法

    package com.bjsxt.dao.impl;
    
    import com.bjsxt.model.User;
    
    public class UserDAOImpl2 extends UserDAOImpl {
        @Override
        public void save(User user) {
            
            System.out.println("save start...");
            super.save(user);
            
        }
    }
    UserDAOImpl2

      注:配置文件被注入到UserService的bean的class要改为UserDAOImpl2,下面也一样

      看似实现了效果,但是这样很不灵活,因为只能继承一个类,而且父类发生变化,子类也必须跟着做出改变,我们可以再添加一个类继承UserDAOImpl,但是采用组合的方法

    package com.bjsxt.dao.impl;
    
    import com.bjsxt.aop.LogInterceptor;
    import com.bjsxt.dao.UserDAO;
    import com.bjsxt.model.User;
    
    public class UserDAOImpl3 implements UserDAO {
        
        private UserDAO userDAO = new UserDAOImpl();
        
        public void save(User user) {
            System.out.println("save start...");
            /*new LogInterceptor().beforeMethod(null);*/
            userDAO.save(user);
            
            
        }
    
        /*public void delete() {
            // TODO Auto-generated method stub
            
        }*/
    }
    UserDAOImpl3

      问题又来了,如果系统有500个需要被注入的bean,每个bean都有一些操作需要被记录日志,难道要组合500个bean来实现这个功能吗?

      实际上可以给UserDAOImpl产生了一个代理,我们知道在代理模式中代理类除了可以调用目标对象的方法,也可以在方法前后加入自己的逻辑,在这里就是日志记录

      在JAVA基础知识:代理这篇文章中,介绍了Proxy类的静态方法newProxyInstance,这个方法需要三个参数,第一个是类装载器,第二个是目标对象的接口,第三个是InvocationHandler,这个最重要,定义了一个invoke方法,方法中可以调用目标对象的方法,也可以添加日志记录的逻辑代码

      新建一个包com.bjsxt.aop,添加类LogInterceptor继承InvocationHandler

    package com.bjsxt.dao.impl;
    
    import com.bjsxt.dao.UserDAO;
    import com.bjsxt.model.User;
    
    
    public class UserDAOImpl implements UserDAO {
    
        public void save(User user) {
            
            //Hibernate
            //JDBC
            //XML
            //NetWork
            System.out.println("user saved!");
        }
    
        public void delete() {
            System.out.println("user deteleted");
            
        }
    
    }
    UserDAOImpl
    package com.bjsxt.aop;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class LogInterceptor implements InvocationHandler {
        private Object target;
        
        public Object getTarget() {
            return target;
        }
    
        public void setTarget(Object target) {
            this.target = target;
        }
    
        public void beforeMethod(Method m) {
            
            System.out.println(m.getName() + " start");
        }
    
        public Object invoke(Object proxy, Method m, Object[] args)
                throws Throwable {
            beforeMethod(m);
            m.invoke(target, args);
            return null;
        }
    }
    InvocationHandler接口的实现类
        @Test
        public void testProxy() {
            UserDAO userDAO = new UserDAOImpl();
            LogInterceptor li = new LogInterceptor();
            li.setTarget(userDAO);
            UserDAO userDAOProxy = (UserDAO)Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), userDAO.getClass().getInterfaces(), li);
            System.out.println(userDAOProxy.getClass());
            userDAOProxy.delete();
            userDAOProxy.save(new User());
            
        }
    单元测试

      我们只需要写一次日志记录的代码,就完成delete和add用户的日志记录工作

      项目结构如下:

  • 相关阅读:
    【Android】【踩坑日记】RecyclerView获取子View的正确姿势
    【Thinking in Java】编写构造器时应注意:尽量避免调用其他非private方法
    为什么匿名内部类只能访问final变量【转】
    【Thinking in Java】类和对象的初始化过程
    【Thinking in Java】Java Callable的使用
    【算法与数据结构】二叉搜索树的Java实现
    【Thinking in Java】组合、继承和代理的区别
    【面试经历】腾讯一二面分享与总结
    【面试经历】腾讯、网易有道和阿里的笔试分享及自我总结
    《Unity預計算即時GI》笔记:三、Clusters和总结
  • 原文地址:https://www.cnblogs.com/SamFlynn/p/4604148.html
Copyright © 2011-2022 走看看