您的位置:首页 > 编程语言 > Java开发

java动态代理详解,并用动态代理和注解实现日志记录功能

2015-07-04 11:39 1086 查看
动态代理的概念

动态代理是程序在运行过程中自动创建一个代理对象来代替被代理的对象去执行相应的操作,例如, 我们有一个已经投入运行的项目中有一个用户DAO类UserDao用来对User对象进行数据库的增删改查操作,但是有一天,要求在对用户的增删改查操作时记录相应的日志,这是怎么办呢?难道我们去直接修改UserDao的源代码,然后在UserDao的每个方法中加入日志记录功能,这显然是不合理的,它违背了java的OCP原则,即对修改关闭对扩张开放。比如改现有的代码如下:

接口类

public interface IUserDao {
public void add(User user);

public User load(int id);

public void delete(int id);

public void update(User user);

}


实现类

public class UserDao implements IUserDao {

public void add(User user) {

System.out.println("user added:" + user);
}

public User load(int id) {
System.out.println("load user, id=" + id);
return null;
}

public void delete(int id) {

System.out.println("deleted user, id=" + id);
}

@Override
public void update(User user) {
System.out.println("updated user:" + user);
}

}


业务类接口

public interface IUserService {
public void add(User user);

public void delete(int id);

public User load(int id);

public void update(User user);
}


业务类实现类

public class UserService implements IUserService {

IUserDao userDao;

public IUserDao getUserDao() {
return userDao;
}

public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}

public void add(User user) {

userDao.add(user);
}

public void delete(int id) {

userDao.delete(id);
}

public User load(int id) {
return userDao.load(id);
}

@Override
public void update(User user) {
userDao.update(user);
}

}


有一天我们现在UserDao的每个方法执行前记录日志,我们定义了一个Logger类来专门输出日志

public class Logger {
public static void log(String info) {
System.out.println(info);
}

}


还实现了一个代理类:

// 1、写一个类继承InvocationHandler
public class LogProxy implements InvocationHandler {
// 2、创建被代理对象
private Object target;
// 3、创建代理对象,参数是要被代理的对象,返回值是代理对象
public static Object getInstance(Object o) {
LogProxy proxy = new LogProxy();
proxy.target = o;
Object result = Proxy.newProxyInstance(o.getClass().getClassLoader(),
o.getClass().getInterfaces(), proxy);
return result;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (method.isAnnotationPresent(LogInfo.class)) { // 检查该方法上是否有LogInf注解
LogInfo li = method.getAnnotation(LogInfo.class); // 取得注解
Logger.log(new Date().toString() + " ---> " + li.value()); // 取得直接的值,输出日志
}
Object o = method.invoke(target, args);
return o;
}

}
自定义Annotation如下:

@Retention(RetentionPolicy.RUNTIME)
public @interface LogInfo {

public String value() default "";
}


一切完了之后,此时如果我们想在对应的方法执行前记录日志,我们只需要在IUserDao的想加入日志的方法手使用LogInfo注解后,在方法执行时就会自动加入日志记录功能了,如下:

public interface IUserDao {
@LogInfo("Add a user")
public void add(User user);

public User load(int id);

@LogInfo("Delete a user")
public void delete(int id);

@LogInfo("Update a user")
public void update(User user);

}


上面只有被加上了@LogInfo注解的方法才会记录日志,如add,delete,update,而load则不会记录日志,所以利用注解可以灵活的控制想要在哪些方法上记录日志

使用

public static void main(String[] args) {
IUserDao userDao = new UserDao();
IUserDao userDaoProxy = (IUserDao) LogProxy.getInstance(userDao);

UserService userService = new UserService();
userService.setUserDao(userDaoProxy);
userService.add(new User());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: