Henry Sun

没有所谓的偶然,一切皆是因果

博客园 首页 新随笔 管理

  在第一节中,我们自己模拟了一个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用户的日志记录工作

  项目结构如下:

posted on 2015-06-27 15:36  Sam Flynn  阅读(582)  评论(0编辑  收藏  举报