package li.aop;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.xpath.XPathConstants;
import li.annotation.Aop;
import li.annotation.Trans;
import li.ioc.Ioc;
import li.util.Files;
import li.util.Log;
import li.util.Reflect;
import li.util.Verify;
import net.sf.cglib.core.NamingPolicy;
import net.sf.cglib.core.Predicate;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.w3c.dom.NodeList;
/**
* Aop增强类生成器,依赖CGLIB
*
* @author li (limingwei@mail.com)
* @version 0.1.1 (2012-09-20)
*/
public class AopEnhancer {
private static final Log log = Log.init();
/**
* AopXml配置文件
*/
private static final String AOP_CONFIG_REGEX = "^.*(config|ioc|aop)\\.xml$";
/**
* 内置AopFilter
*/
private final Map<String, AopFilter> filtersBuiltIn = new HashMap<String, AopFilter>();
/**
* Xml配置的Aop规则
*/
private final List<String[]> xmlAopRules = new ArrayList<String[]>();
/**
* 自定义的NamingPolicy,使Aop子类类名以$Aop结尾
*/
private NamingPolicy namingPolicy;
/**
* 初始化
*/
public AopEnhancer() {
namingPolicy = new NamingPolicy() {// 自定义的NamingPolicy,使Aop子类类名以$Aop结尾
public String getClassName(String prefix, String source, Object key, Predicate names) {
prefix = null == prefix ? "net.sf.cglib.empty.Object" : prefix.startsWith("java") ? "$" + prefix : prefix;
return source.endsWith("Enhancer") ? prefix + "$Aop" : prefix + "$FastClass";
} // http://t.cn/zQo4ydN
};
filtersBuiltIn.put("~!@#trans", new TransFilter());// 内置TransFilter
filtersBuiltIn.put("~!@#readonly", new TransFilter().setReadOnly(true));// 内置 ReadOnly TransFilter
readXmlAopConfig();
}
/**
* 解析XmlAop配置
*/
private void readXmlAopConfig() {
File rootFolder = Files.root();
List<String> fileList = Files.list(rootFolder, AOP_CONFIG_REGEX, true, 1);// 搜索配置文件
log.info("Found ? aop config xml files, at ?", fileList.size(), rootFolder);
for (String filePath : fileList) {
NodeList beanNodes = (NodeList) Files.xpath(Files.build(filePath), "//aop", XPathConstants.NODESET);
for (int length = (null == beanNodes ? -1 : beanNodes.getLength()), i = 0; i < length; i++) {
String type = Files.xpath(beanNodes.item(i), "@class", XPathConstants.STRING).toString();
String method = Files.xpath(beanNodes.item(i), "@method", XPathConstants.STRING).toString();
String aops = Files.xpath(beanNodes.item(i), "@filter", XPathConstants.STRING).toString();
xmlAopRules.add(new String[] { type, method, aops });
}
}
}
/**
* 获取一个方法通过注解配置的AopFilters
*/
private List<AopFilter> getAnnotationFilters(Method method) {
List<AopFilter> filters = new ArrayList<AopFilter>();
Aop aop = method.getAnnotation(Aop.class);
for (int length = (null == aop ? -1 : aop.value().length), i = 0; i < length; i++) {// 如果有@Aop注解,对每一个@Aop.value()的值
AopFilter filter = Ioc.get(aop.value()[i]);// 通过Ioc得到AopFilter
filters.add(null != filter ? filter : Reflect.born(aop.value()[i]));// 非Ioc管理,则直接new
}
Trans trans = method.getAnnotation(li.annotation.Trans.class);
if (null != trans) {// 如果有@Trans注解
filters.add(new TransFilter().setLevel(trans.value() != -1 ? trans.value() + "" : null).setReadOnly(trans.readOnly()));
}// 每个注解都需要new TransFilter(),因为各个的注解值会不一样
return filters;
}
/**
* 获取一个方法通过Xml配置的AopFilters
*/
private List<AopFilter> getXmlFilters(Object target, Method method) {
List<AopFilter> filters = new ArrayList<AopFilter>();
for (String[] role : xmlAopRules) {// 所有的规则
if (Verify.regex(target.getClass().getName(), role[0]) && Verify.regex(method.getName(), role[1])) {// method.getDeclaringClass() or target.getClass()
String[] names = role[2].split(",");// 所有Aop切入类
for (String name : names) {
AopFilter filter = Ioc.get(name);// 通过Ioc得到AopFilter
if (null == (null == filter ? filter = filtersBuiltIn.get("~!@#" + name) : filter)) {// 无Ioc配置则取内置,若无则报异常
throw new RuntimeException("AopFilter " + name + " not found <aop class=\"" + role[0] + "\" method=\"" + role[1] + "\" filter=\"" + role[2] + "\" />");
}
filters.add(filter);// 为空时搜索内置的AopFilter
}
}
}
return filters;
}
/**
* 获取一个方法的所有AopFilters
*/
private List<AopFilter> getFilters(Object target, Method method) {
List<AopFilter> filters = this.getAnnotationFilters(method);
filters.addAll(this.getXmlFilters(target, method));// 先加载注解 Aop,后Xml Aop,使注解配置覆盖Xml配置
return filters;
}
/**
* 生成一个Aop增强的对象
*/
public Object create(Class<?> type) {
Enhancer enhancer = new Enhancer(); // 创建代理
enhancer.setNamingPolicy(namingPolicy);
enhancer.setSuperclass(type);
enhancer.setCallback(new MethodInterceptor() {// 设置callback,使用AopChain代理执行方法
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return new AopChain(target, method, args, getFilters(target, method), proxy).doFilter().getResult();
}// 使用AopChian代理执行这个方法并返回值
});
return enhancer.create();// 创建代理对象
}
}