为了能更为深入理解Spring原理,知道怎么用还不如会自己做,于是便动手完成了这个集成框架。功能点仿照Spring,包括IOC中的注入、延迟加载、装配集合等等一系列功能,AOP是采用jdk动态代理实现的,没用CGLIB,因此,被代理的对象必须继承某个接口。
源代码主要为:
ConfigManager.java 负责解析xml、装配bean、获取bean等操作,是框架最重要的类。
ParserHelper.java 辅助XML解析的类。
ProxyHandler.java 代理类,用于支持AOP功能。
ProceedingJoinPoint.java 为了能够实现代理链,封装了Method、Object、args对象以及execute()方法。
AspectInfo.java 切面信息对象。
autumn.dtd DTD文件,用于约束配置文件语法。
源码如下:
ConfigManager.java
package cn.seu.bingluo.ioc;import java.lang.reflect.InvocationTargetException;/* * By Bingluo 2012.8.17 * cose.seu.edu.cn */public class ConfigManager { // 存放dom private Document dom; private Element root; // 从配置中生成的bean放入map中 private HashMapbeans = new HashMap (); // 在构造函数时,初始化dom树 public ConfigManager(String xmlUrl) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setIgnoringElementContentWhitespace(true); DocumentBuilder db; try { db = factory.newDocumentBuilder(); dom = db.parse(xmlUrl); dom.normalize(); root = dom.getDocumentElement(); System.out.println("IOC/AOP初始化开始..."); initBeans(); System.out.println("IOC/AOP初始化结束..."); } catch (Exception e) { e.printStackTrace(); } } // 初始化配置文件中所有非懒加载的bean private void initBeans() { for (Node node = root.getFirstChild(); node != null; node = node .getNextSibling()) { // 延迟加载Bean if (node.getNodeName().equals("bean") && ((Element) node).hasAttribute("lazy-init") && ((Element) node).getAttribute("lazy-init") .equals("true")) continue; else if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals("bean")) // 普通bean // 创建后,存入map中 beans.put(((Element) node).getAttribute("id"), initBean(node)); else if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals("aop-config")) { // aop配置 initAOP(node); } } } //AOP配置 private void initAOP(Node aopConfig) { for (Node node = aopConfig.getFirstChild(); node != null; node = node .getNextSibling()) { // 为切面节点,配置增强 if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals("aspect")) { initAspect(node); } } } //配置AOP切面 private void initAspect(Node aspect) { String aspectRef = ((Element) aspect).getAttribute("ref"); Object adviceBean = null; String expression = ""; Method beforeMethod = null; Method aroundMethod = null; Method afterMethod = null; if (beans.containsKey(aspectRef)) { // 在beans的map中发现已初始化过该bean adviceBean = beans.get(aspectRef); } else { // 未初始化过该bean Node e = dom.getElementById(aspectRef); if (e.getNodeName().equals("bean")) { // 递归调用,初始化被引用的bean adviceBean = initBean(e); } } // 获取切点 // ***************1个切面默认最多只有1个切点、1个前置增强、1个后置增强、1个环绕增强 Node pointcutNode = ParserHelper.getNode(aspect, "pointcut"); expression = ((Element) pointcutNode).getAttribute("expression"); // 获取该切面的增强 for (Node currentNode = aspect.getFirstChild(); currentNode != null; currentNode = currentNode .getNextSibling()) { if (currentNode.getNodeType() != Node.ELEMENT_NODE) continue; // 为相应的增强赋值 String methodName = ((Element) currentNode).getAttribute("method"); try { if (currentNode.getNodeName().equals("before")) { beforeMethod = adviceBean.getClass().getMethod(methodName); } else if (currentNode.getNodeName().equals("around")) { aroundMethod = adviceBean.getClass().getMethod(methodName, ProceedingJoinPoint.class); } else if (currentNode.getNodeName().equals("after")) { afterMethod = adviceBean.getClass().getMethod(methodName); } } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } // 将该切面交给代理维护 AspectInfo aspectInfo = new AspectInfo(expression, adviceBean, beforeMethod, aroundMethod, afterMethod); ProxyHandler.addAspectInfo(aspectInfo); } //初始化Bean @SuppressWarnings({ "rawtypes", "unchecked" }) private Object initBean(Node node) { // 初始化的类型 Class c = null; // 需要初始化的bean Object object = null; // 生成对象 try { c = Class.forName(((Element) node).getAttribute("class")); object = c.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } // 如果此bean为基本类型bean if (isPrimitive(((Element) node).getAttribute("class")) || ((Element) node).hasAttribute("value")) { object = getInstanceForName(((Element) node).getAttribute("class"), ((Element) node).getAttribute("value")); return object; } boolean constructorInit = false;// 是否为构造函数注入 ArrayList parameterTypes = new ArrayList (); ArrayList
ParserHelper.java
package cn.seu.bingluo.ioc;import org.w3c.dom.Node;/* * By Bingluo 2012.8.17 * cose.seu.edu.cn * Parser辅助方法 */public class ParserHelper { //查看Node中是否存在名为name的子节点 public static boolean containNode(Node node,String name){ for (Node currentNode = node.getFirstChild(); currentNode!=null; currentNode = currentNode.getNextSibling()) { if (currentNode.getNodeName().equals(name)) { return true; } } return false; } //返回名称对应的节点 public static Node getNode(Node node, String name){ for (Node currentNode = node.getFirstChild(); currentNode!=null; currentNode = currentNode.getNextSibling()) { if (currentNode.getNodeName().equals(name)) { return currentNode; } } return null; }}
ProxyHandler.java
package cn.seu.bingluo.ioc;import java.lang.reflect.InvocationHandler;/* * 代理类 * 运用jdk动态代理实现,要求前提是被代理对象实现接口 */public class ProxyHandler implements InvocationHandler { // 存储所有切面 private static HashMapaspectInfos = new HashMap (); // 被代理的对象 private Object target = null; public ProxyHandler(Object target) { this.target = target; } public static void addAspectInfo(AspectInfo aspectInfo) { aspectInfos.put(aspectInfo.getExpression(), aspectInfo); } // 获取代理实例 public Object getProxyInstance() { if (target == null) { return null; } return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } // 获取代理实例 public Object getProxyInstance(Object target) { if (target == null) { return null; } this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ArrayList aspects = new ArrayList (); Set > entrySet = aspectInfos.entrySet(); Object result = null; //遍历切面列表,找到对应的切面 for (Entry entry : entrySet) { AspectInfo aspectInfo = entry.getValue(); Object adviceBean = aspectInfo.getAdviceBean(); String expression = aspectInfo.getExpression(); Pattern pattern = Pattern.compile(expression); Matcher matcher = pattern.matcher(target.getClass().getName() + "." + method.getName()); if (matcher.find()) { AspectInfo aspect = new AspectInfo(); aspect.setAdviceBean(adviceBean); aspect.setBeforeMethod(aspectInfo.getBeforeMethod()); aspect.setAroundMethod(aspectInfo.getAroundMethod()); aspect.setAfterMethod(aspectInfo.getAfterMethod()); aspects.add(aspect); } } // 执行before增强 for (AspectInfo aspect : aspects) { Object adviceBean = aspect.getAdviceBean(); if (aspect.getBeforeMethod() != null) { aspect.getBeforeMethod().invoke(adviceBean, new Object[]{}); } } // 执行around增强 Object aroundAdviceBean = target; Method aroundAdviceMethod = method; Object[] aroundAdviceArgs = args; for (AspectInfo aspect : aspects) { Object adviceBean = aspect.getAdviceBean(); if (aspect.getAroundMethod() != null) { aroundAdviceArgs = new Object[] { new ProceedingJoinPoint( aroundAdviceBean, aroundAdviceMethod, aroundAdviceArgs) }; aroundAdviceBean = adviceBean; aroundAdviceMethod = aspect.getAroundMethod(); } } result = aroundAdviceMethod.invoke(aroundAdviceBean, aroundAdviceArgs); // 执行After增强 for (AspectInfo aspect : aspects) { Object adviceBean = aspect.getAdviceBean(); if (aspect.getAfterMethod() != null) { aspect.getAfterMethod().invoke(adviceBean, new Object[]{}); } } return result; }}
ProceedingJoinPoint.java
package cn.seu.bingluo.ioc;import java.lang.reflect.InvocationTargetException;/* * 用于处理AOP代理链时,封装相关信息作为统一参数进行传递 */public class ProceedingJoinPoint { private Object object;//被代理的对象 private Method method;//被代理的方法 private Object[] args;//方法相应的参数 public ProceedingJoinPoint(Object object, Method method, Object[] args){ this.object = object; this.method = method; this.args = args; } //执行目标函数 public Object excute(){ Object result = null; try { result = method.invoke(object, args); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return result; }}
AspectInfo.java
package cn.seu.bingluo.ioc;import java.lang.reflect.Method;/* * 切面信息Bean * 每1个切面最多只有: * 1个切点expression * 1个增强bean * 1个前置增强、环绕增强、后置增强 */public class AspectInfo { private String expression = ""; private Object adviceBean = null; private Method beforeMethod = null; private Method aroundMethod = null; private Method afterMethod = null; public AspectInfo(){ } public AspectInfo(String expression, Object adviceBean, Method beforeMethod, Method aroundMethod, Method afterMethod) { setExpression(expression); setAdviceBean(adviceBean); setBeforeMethod(beforeMethod); setAroundMethod(aroundMethod); setAfterMethod(afterMethod); } public String getExpression() { return expression; } public void setExpression(String expression) { this.expression = expression; } public Object getAdviceBean() { return adviceBean; } public void setAdviceBean(Object adviceBean) { this.adviceBean = adviceBean; } public Method getBeforeMethod() { return beforeMethod; } public void setBeforeMethod(Method beforeMethod) { this.beforeMethod = beforeMethod; } public Method getAroundMethod() { return aroundMethod; } public void setAroundMethod(Method aroundMethod) { this.aroundMethod = aroundMethod; } public Method getAfterMethod() { return afterMethod; } public void setAfterMethod(Method afterMethod) { this.afterMethod = afterMethod; }}
autumn.dtd
接下来,我们来测试一下框架功能是否实现!
先测试IOC,测试bean的装配,写个POJO类
TestIOCBean.java
package cn.seu.bingluo.ioc;import java.util.Collection;/* * By Bingluo 2012.8.17 * cose.seu.edu.cn * 测试Bean */public class TestIOCBean { private int a; private Integer aa; private String b; private TestIOCBean innerBean; private TestIOCBean outterBean; private Collectioncollection; private Map map; private Properties props; public TestIOCBean(){ } public TestIOCBean(int a,String b,TestIOCBean oBeanTest) { this.setA(a); this.setB(b); this.setOutterBean(oBeanTest); } public Integer getA() { return a; } public void setA(int a){ this.a = a; } public Integer getAa() { return aa; } public void setAa(Integer aa) { this.aa = aa; } public String getB() { return b; } public void setB(String b) { this.b = b; } public TestIOCBean getInnerBean() { return innerBean; } public void setInnerBean(TestIOCBean innerBean) { this.innerBean = innerBean; } public TestIOCBean getOutterBean() { return outterBean; } public void setOutterBean(TestIOCBean outterBean) { this.outterBean = outterBean; } public Collection getCollection() { return collection; } public void setCollection(Collection collection) { this.collection = collection; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public Properties getProps() { return props; } public void setProps(Properties props) { this.props = props; }}
再写一个Service类,用于测试AOP功能,注意,框架AOP功能是用JDK动态代理实现的,故必须继承自某个接口:
ITestAOPBean.java
package cn.seu.bingluo.ioc;/* * 必须被继承才能实现AOP代理 */public interface ITestAOPBean { public int shout();}
TestAOPBean.java
package cn.seu.bingluo.ioc;/* * 测试AOP功能 * 用jdk动态代理实现,故必须继承接口 */public class TestAOPBean implements ITestAOPBean{ private String name = "aop-test"; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int shout() { System.out.println("Hello, My name is "+name); return 1; }}
再为这个service写一个增强类,将该类中的方法织入service的shout()中。
Advice.java
package cn.seu.bingluo.ioc;/* * 增强类 * 用于测试AOP功能 */public class Advice { public void Before(){ System.out.println("Before..."); } public Object Around(ProceedingJoinPoint joinPoint){ System.out.println("Before-around..."); Object object = joinPoint.excute(); System.out.println("After-around..."); return object; } public void After(){ System.out.println("After..."); }}
到这里,重点来了,我们就需要将bean配置起来了,建立xml文件:
config.xml(注意用dtd约束)
im' props' value: s3 im' props' value: s4
最后,再写一个main函数驱动一下,就大功告成啦!
Driver.java
package cn.seu.bingluo.ioc;import java.util.Iterator;public class Driver { /** * @param args */ @SuppressWarnings("rawtypes") public static void main(String[] args) { // 测试桩 // 解析IOC配置文件 ConfigManager configManager = new ConfigManager("config.xml"); // 获取id为“bean”的Bean TestIOCBean beanTest = (TestIOCBean) configManager.getBean("bean"); System.out.println(beanTest.getA() + ":" + beanTest.getAa() + ":" + beanTest.getB()); System.out.println(beanTest.getInnerBean().getB()); System.out.println(beanTest.getInnerBean().getOutterBean().getB()); String string = (String) configManager.getBean("str1"); System.out.println(string); string = (String) configManager.getBean("str2"); System.out.println(string); // 装配集合测试 Listlist = (List ) beanTest.getCollection(); System.out.println(list.get(0)); Set set = (Set ) beanTest.getInnerBean().getCollection(); for (Iterator it = set.iterator(); it.hasNext();) { System.out.println("value=" + it.next().toString()); } TestIOCBean outterBeanTest = (TestIOCBean) configManager .getBean("outterBean"); System.out.println(outterBeanTest.getMap().get("s1")); System.out.println(outterBeanTest.getProps().get("s3")); //测试构造函数注入 TestIOCBean constructorBeanTest = (TestIOCBean) configManager .getBean("constructorInit"); System.out.println(constructorBeanTest.getA() + constructorBeanTest.getB() + constructorBeanTest.getOutterBean().getAa()); //测试AOP功能 System.out.println("\n***************** AOP测试 *****************"); ITestAOPBean testBean = (ITestAOPBean) configManager.getBean("shoutBean"); testBean.shout(); }}
运行结果:
功能算是实现啦!
如果有发现什么问题或者不足的话,欢迎给我留言或者发送邮件。谢谢!
邮箱:bingluo#foxmail.com(#转为@)