温习温习 aop的原理

在我工作这几年里,spring aop 用得最多的有两点

1 事务通过aop来配置
2 判断service 或者dao 层 运行时间

那么原理是怎么样的呢? 我也没有想去细致的理解

首先 我们想实现一个功能
请看如下的类:



packagecom.aop;

/**
* Created with IntelliJ IDEA.
* User: zhangyong
* Date: 13-2-11
* Time: 下午10:23
* To change this template use File | Settings | File Templates.
*/
publicinterfaceIHello {

publicvoidsayHello();

}
1111
实现类如下:

packagecom.aop.impl;

importcom.aop.IHello;

importjava.lang.reflect.Proxy;

/**
* Created with IntelliJ IDEA.
* User: zhangyong
* Date: 13-2-11
* Time: 下午10:24
* To change this template use File | Settings | File Templates.
*/
publicclassIHelloImplimplementsIHello {

@Override
publicvoidsayHello() {
System.out.println("Hello come on");
}



}


2 添加代理类来绑定接口

代理类首先 需要实现 InvocationHandler

所以 定义个代理类





packagecom.aop;

importorg.apache.log4j.Logger;

importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.lang.reflect.Proxy;
importjava.sql.Connection;

/**
* hello的代理类
* User: zhangyong
* Date: 13-2-11
* Time: 下午10:26
* To change this template use File | Settings | File Templates.
*/
publicclassHelloProxyimplementsInvocationHandler {

privatestaticLogger logger = Logger.getLogger(HelloProxy.class);

privateIHello hello;

publicHelloProxy(IHello hello) {
this.hello = hello;
}

publicstaticIHello newInstance(IHello hello) {
InvocationHandler handler =newHelloProxy(hello);
ClassLoader classLoader = IHello.class.getClassLoader();

return(IHello) Proxy.newProxyInstance(classLoader,newClass[]{IHello.class}, handler);
}

@Override
publicObject invoke(Object proxy, Method method, Object[] args)throwsThrowable {
logger.info("I am invoking starting");
Object returnObj = method.invoke(hello, args);
logger.info("I am invoking ending");
returnreturnObj;
}


}


ok ! 代理类写好了 我们需要写意个测试类 :



packagecom.aop;

importcom.aop.impl.IHelloImpl;
importorg.apache.commons.logging.Log;
importorg.apache.commons.logging.LogFactory;

importjava.sql.Connection;

/**
* 测试aop
* User: zhangyong
* Date: 13-2-11
* Time: 下午10:25
* To change this template use File | Settings | File Templates.
*/
publicclassTestAop {

privatestaticfinalLog log = LogFactory.getLog(Connection.class);

publicstaticvoidmain(String[] args) {
IHello hello = HelloProxy.newInstance(newIHelloImpl());
hello.sayHello();
}

}



运行结果如下:

2013-02-15 17:26:18,844 INFO main com.aop.HelloProxy:invoke(36) - I am invoking starting
Hello come on
2013-02-15 17:26:18,847 INFO main com.aop.HelloProxy:invoke(38) - I am invoking ending


另外在mybatis 里 当我们在log4j里配置好 输出的时候 比如:


log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG


就会打印响应的sql ,在mybatis里 涉及到的类是: ConnectionLogger




package org.apache.ibatis.logging.jdbc;

import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.reflection.ExceptionUtil;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;

/**
* Connection proxy to add logging 添加日志的代理(好方法)
*/
public class ConnectionLogger extends BaseJdbcLogger implements InvocationHandler {

private static final Log log = LogFactory.getLog(Connection.class);

private Connection connection;

private ConnectionLogger(Connection conn) {
super();
this.connection = conn;
if (log.isDebugEnabled()) {//在log4j中配置
log.debug("ooo Connection Opened");
}
}

public Object invoke(Object proxy, Method method, Object[] params)
throws Throwable {
try {
if ("prepareStatement".equals(method.getName())) {
PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
stmt = PreparedStatementLogger.newInstance(stmt, (String) params[0]);
return stmt;
} else if ("prepareCall".equals(method.getName())) {
PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
stmt = PreparedStatementLogger.newInstance(stmt, (String) params[0]);
return stmt;
} else if ("createStatement".equals(method.getName())) {
Statement stmt = (Statement) method.invoke(connection, params);
stmt = StatementLogger.newInstance(stmt);
return stmt;
} else if ("close".equals(method.getName())) {
if (log.isDebugEnabled()) {
log.debug("xxx Connection Closed");
}
return method.invoke(connection, params);
} else {
return method.invoke(connection, params);
}
} catch (Throwable t) {
Throwable t1 = ExceptionUtil.unwrapThrowable(t);
log.error("Error calling Connection." + method.getName() + ':', t1);
throw t1;
}

}

/**
* Creates a logging version of a connection
*
* @param conn - the original connection
* @return - the connection with logging
*/
public static Connection newInstance(Connection conn) {
InvocationHandler handler = new ConnectionLogger(conn);
ClassLoader cl = Connection.class.getClassLoader();
return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler);
}

/**
* return the wrapped connection
*
* @return the connection
*/
public Connection getConnection() {
return connection;
}

}


它的调用方式是:


/** 根据日志级别 封装connection 若是DEBUG级别 则封装log **/
private Connection wrapConnection(Connection connection) {
if (log.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection);
} else {
return connection;
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值