通过以下两篇文章,便可以自己做一个aop和ioc的结合,并通过xml文件进行动态的配置
Spring 的aop实现原理:http://blog.csdn.net/lr222584/article/details/54755031
自己写一个简单的Spring IOC容器:http://blog.csdn.net/lr222584/article/details/54744583
包结构:
Beans.xml
<beans>
<bean id="a" class="demo.myspring.impl.AImpl"/>
<bean id="b" class="demo.myspring.impl.BImpl">
<property name="a" bean = "a" />
</bean>
<bean id="c" class="demo.myspring.impl.CImpl"/>
<!-- 生成一个动态代理对象 -->
<aop>
<!-- 切面类 -->
<aspect id = "test" ref = "c">
<!-- method要切入的方法 ,pointcut-ref为目标类,括号内为方法名 -->
<before method = "print" pointcut-ref="demo.myspring.impl.BImpl(print)"/>
</aspect>
</aop>
</beans>
ClassPathXmlApplicationContext类
package demo.myspring.core;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import demo.myspring.BeanFactory;
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beans = new HashMap<String,Object>();
private Map<String,String> beansXml = new HashMap<String,String>();
public ClassPathXmlApplicationContext() throws Exception{
SAXBuilder sb = new SAXBuilder();//新建xml解析器
Document xmlDoc = sb.build(this.getClass().getClassLoader().
getResourceAsStream("demo/myspring/conf/beans.xml"));//构造文档对象
Element root = xmlDoc.getRootElement();//获取根元素
List<Element> list = root.getChildren("bean");//获取根元素下所有名字为bean的元素
//遍历所有的bean元素,并将其放入beans中
for(int i = 0;i<list.size();i++){
Element e = (Element)list.get(i);//获取Element元素
String id = e.getAttributeValue("id");//获取property的id属性的值
String clazz = e.getAttributeValue("class");//获取property的class属性的值
beansXml.put(clazz, id);
Object o = Class.forName(clazz).newInstance();//利用反射生成一个具体的实例
System.out.println(" id: "+id+" class: "+clazz);
beans.put(id, o);//将bean放入一个HashMap
//遍历bean下的所有properyt属性,并调用setter方法,将值注入给对应的属性
if(e.getChild("property")!=null){
for(Element p : (List<Element>)e.getChildren("property")){
String name = p.getAttributeValue("name");
String bean = p.getAttributeValue("bean");
Object beanObject = beans.get(bean);
String methodName = "set" + name.substring(0,1).toUpperCase()+ name.substring(1);
System.out.println("setter method name = " +methodName);
Method m = o.getClass().getMethod(methodName,beanObject.getClass().getInterfaces()[0]);
m.invoke(o,beanObject);//调用setter方法
}
}
}
Element aop = root.getChild("aop");
//校验容器是否使用aop,如果使用aop则用代理类替换掉beans中对应key的value
if(aop!=null){
Element aspect = aop.getChild("aspect");
String id=aspect.getAttributeValue("id");
String ref=aspect.getAttributeValue("ref");
//从beans中获取要切入的类
Object proxy=beans.get(ref);
Element before = aspect.getChild("before");
if(before!=null){
String pointcut_ref = before.getAttributeValue("pointcut-ref");
int subscript1 = pointcut_ref.indexOf("(");
int subscript2 = pointcut_ref.indexOf(")");
//目标类的名字和方法的名字
String targetClassName = pointcut_ref.substring(0,subscript1);
String methodName= pointcut_ref.substring(subscript1+1,subscript2);
String targetId=beansXml.get(targetClassName);
//获取目标类和方法
Object target = beans.get(targetId);
//切入的方法
String proxyMethodName= before.getAttributeValue("method");
//生成代理类,并替换beans中对应id的value
DynaProxy dynaProxy = new DynaProxy();
dynaProxy.setPointcut("before");
dynaProxy.setTargetMethod(methodName);
dynaProxy.setProxyMethodName(proxyMethodName);
beans.put(targetId,dynaProxy.bind(target,proxy));
}
}
}
public Object getBean(String id) {
return beans.get(id);
}
}
DynaProxy类
package demo.myspring.core;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynaProxy implements InvocationHandler {
//调用对象
private Object proxy;
//切入方法名
private String proxyMethodName;
//要切入方法的位置
private String pointcut;
//目标对象
private Object target;
//目标方法
private String targetMethod;
public void setProxyMethodName(String proxyMethodName) {
this.proxyMethodName = proxyMethodName;
}
public void setPointcut(String pointcut) {
this.pointcut = pointcut;
}
public void setTargetMethod(String targetMethod) {
this.targetMethod = targetMethod;
}
//返回一个target的动态代理类
public Object bind(Object target,Object proxy){
this.target=target;
this.proxy=proxy;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
}
//调用target任何方法,都会调用动态代理类的invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
//反射得到操作者的实例
Class clazz = this.proxy.getClass();
//反射得到操作者的Start方法
Method proxyMethod = clazz.getMethod(proxyMethodName);
//如果是前置通知
if("before".equals(pointcut)&&(method.getName().equals(targetMethod))){
proxyMethod.invoke(this.proxy,null);
method.invoke(this.target,null);
}else{
method.invoke(this.target,null);
}
return result;
}
}
A接口
package demo.myspring;
public interface A {
public void print();
}
B接口
package demo.myspring;
public interface B {
public void print();
public void print1();
}
C接口
package demo.myspring;
public interface C {
public void print();
}
BeanFactory接口
public interface BeanFactory {
public Object getBean(String id);
}
AImpl类
package demo.myspring.impl;
import demo.myspring.A;
public class AImpl implements A {
public void print() {
System.out.println("AImpl invoked!");
}
}
BImpl类
package demo.myspring.impl;
import demo.myspring.A;
public class BImpl implements demo.myspring.B {
A a;
public void setA(A a) {
this.a = a;
}
public void print(){
System.out.println("BImpl invoked!");
}
public void print1(){
System.out.println("aaaaaa");
}
}
CImpl类
package demo.myspring.impl;
import demo.myspring.C;
public class CImpl implements C{
public void print(){
System.out.println("CImpl invoked!");
}
}
Test类
package demo.myspring.test;
import demo.myspring.B;
import demo.myspring.core.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) throws Exception{
ClassPathXmlApplicationContext cpxa = new ClassPathXmlApplicationContext();
B b = (B) cpxa.getBean("b");
System.out.println("***********************");
b.print();//执行b.print前,会执行CImpl的print方法
System.out.println("***********************");
b.print1();
}
}
执行Test后,结果如下
这是只一个非常简单的例子,其中还有很多问题,但已经能通过配置xml文件动态实现aop的功能。