最近在看Spring的ioc和aop相关的知识点,看了一点官方的源码,一知半解,只能说对这俩个东西有个宏观的大致的了解,具体实现细节还是不是很清晰。于是参考了网上的aop和ioc简单实现代码,将二者简单整合了起来。当然,这个demo写的还是问题很多,可能得慢慢思考如何进行修改和优化。由于对xml解析的水平不太高,xml解析部分的代码原作者没有封装成函数,可以说是一个遗憾,未来有时间希望可以修改一下。
下面介绍一下大致的实现步骤:
- 加载xml文件,遍历其标签
- 获取标签中的id和class属性,加载class属性的类,并创建bean
- 遍历标签中的属性,获取属性值,并将属性值填充到bean中
- 将bean存储到bean容器中
- 后处理,找出所有的实现了InvocationHandler接口的类(这些就是advice类)。这个handler对应的切面逻辑类已经在bean的初始化的时候被注入了。从handler的属性中获取需要被代理的bean,创建jdk动态代理,将代理类重新存储到bean容器中。
- 通过getBean方法获取代理类,调用其方法进行测试
以下是代码清单:
ioc.xml //bean的配置文件
SimpleIOC //IOC和AOP的实现类
Car //IOC和AOP的测试接口
DazhongCar //IOC和AOP的测试类
Advice //继承了InvocationHandler接口的接口
AfterMethodInvocation //后置通知的逻辑需实现接口(需要使用被代理类的方法返回值)
MethodInvocation //前置通知的逻辑需实现接口
AfterAdvice // 代理类,后置通知实现类,实现Advice
BeforeAdvice //代理类,前置通知方法实现类,实现Advice
AfterTask //后置通知方法实现逻辑
BeforeTask //前置通知方法实现逻辑
Test //测试类
以下是详细代码
ioc.xml
SimpleIOC.java
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SimpleIOC {
private Map beanMap = new HashMap();
public SimpleIOC(String location) throws Exception {
loadBeans(location);
}
public Object getBean(String name) {
Object bean = beanMap.get(name);
if (bean == null) {
throw new IllegalArgumentException("there is no bean with name " + name);
}
return bean;
}
private void loadBeans(String location) throws Exception {
// 加载 xml 配置文件
InputStream inputStream = new FileInputStream(location);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
Element root = doc.getDocumentElement();
NodeList nodes = root.getChildNodes();
// 遍历 标签
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
String id = ele.getAttribute("id");
String className = ele.getAttribute("class");
// 加载 beanClass
//反射
Class beanClass = null;
try {
beanClass = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return;
}
// 创建 bean
Object bean = beanClass.newInstance();
// 遍历 标签
NodeList propertyNodes = ele.getElementsByTagName("property");
if(propertyNodes==null||propertyNodes.getLength()==0) registerBean(id, bean);
for (int j = 0; j < propertyNodes.getLength(); j++) {
Node propertyNode = propertyNodes.item(j);
if (propertyNode instanceof Element) {
Element propertyElement = (Element) propertyNode;
String name = propertyElement.getAttribute("name");
String value = propertyElement.getAttribute("value");
// 利用反射将 bean 相关字段访问权限设为可访问
Field declaredField = bean.getClass().getDeclaredField(name);
declaredField.setAccessible(true);
if (value != null && value.length() > 0) {
// 将属性值填充到相关字段中
declaredField.set(bean, value);//set值
} else {
String ref = propertyElement.getAttribute("ref");//如果是一个自定义的对象,那么需要去找这个对象的值
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("ref config error");
}
// 将引用填充到相关字段中
declaredField.set(bean, getBean(ref));
}
// 将 bean 注册到 bean 容器中
registerBean(id, bean);
}
}
}
}
//bean加载完成
postProcessAfterInitialization();
}
private void postProcessAfterInitialization() {
beanMap.forEach((beanName,bean) -> {
//是否需要增强
if(bean instanceof InvocationHandler){
createProxy(bean);
}
});
}
private void createProxy(Object advice) {
if(advice instanceof BeforeAdvice){
String beanName = ((BeforeAdvice) advice).getBeanName();
Object bean = beanMap.get(beanName);
if(bean==null){
new Exception("这个bean "+beanName+"还没被初始化或者这个advice没有绑定bean");
}
Object proxy = Proxy.newProxyInstance(SimpleIOC.class.getClassLoader(),
bean.getClass().getInterfaces(), (BeforeAdvice)advice);
registerBean(beanName, proxy);//重新注册这个bean为它的代理类
}else if(advice instanceof AfterAdvice){ //后置增强
String beanName = ((AfterAdvice) advice).getBeanName();
Object bean = beanMap.get(beanName);
if(bean==null){
new Exception("这个bean "+beanName+"还没被初始化或者这个advice没有绑定bean");
}
Object proxy = Proxy.newProxyInstance(SimpleIOC.class.getClassLoader(),
bean.getClass().getInterfaces(), (AfterAdvice)advice);
registerBean(beanName, proxy);//重新注册这个bean为它的代理类
}
}
private void registerBean(String id, Object bean) {
beanMap.put(id, bean);
}
}
Car.java
public interface Car {
public int driver();
}
DazhongCar.java
public class DazhongCar implements Car {
private String name;
private String length;
private String width;
private String height;
private Wheel wheel;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLength() {
return length;
}
public void setLength(String length) {
this.length = length;
}
public String getWidth() {
return width;
}
public void setWidth(String width) {
this.width = width;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public Wheel getWheel() {
return wheel;
}
public void setWheel(Wheel wheel) {
this.wheel = wheel;
}
/* (non-Javadoc)
* @see spring.aopAndIoc.Car#driver()
*/
@Override
public int driver() {
System.out.println("driver Dazhong car");
return 1;//运行返回值,测试后置增强
}
}
Advice.java
public interface Advice extends InvocationHandler{
}
AfterMethodInvocation.java
public interface AfterMethodInvocation {
void invoke(Object o);
}
AfterAdvice.java
import java.lang.reflect.Method;
public class AfterAdvice implements Advice{
private Object bean;
private AfterMethodInvocation afterInvocation;
private String beanName;
public Object getBean() {
return bean;
}
public void setBean(Object bean) {
this.bean = bean;
}
public AfterMethodInvocation getAfterInvocation() {
return afterInvocation;
}
public void setAfterInvocation(AfterMethodInvocation afterInvocation) {
this.afterInvocation = afterInvocation;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
/* (non-Javadoc)
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = method.invoke(bean, args);
// 在目标方法执行后调用通知,并使用目标方法的返回值
afterInvocation.invoke(ret);
return ret;
}
}
BeforeAdvice.java
import java.lang.reflect.Method;
public class BeforeAdvice implements Advice{
private Object bean;
private String beanName;
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
private MethodInvocation methodInvocation;
public Object getBean() {
return bean;
}
public void setBean(Object bean) {
this.bean = bean;
}
public MethodInvocation getMethodInvocation() {
return methodInvocation;
}
public void setMethodInvocation(MethodInvocation methodInvocation) {
this.methodInvocation = methodInvocation;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在目标方法执行前调用通知
methodInvocation.invoke();
return method.invoke(bean, args);//代理对象调用真实目标对象的方法去处理用户请求
}
}
AfterTask.java
public class AfterTask implements AfterMethodInvocation{
//private Object bean
@Override
public void invoke(Object o) {
System.out.println("bean 方法执行的结果是"+o);
}
}
BeforeTask.java
public class BeforeTask implements MethodInvocation{
/* (non-Javadoc)
* @see spring.aopAndIoc.MethodInvocation#invoke()
*/
@Override
public void invoke() {
System.out.println("before the method");
}
}
Test.java
public class Test {
public static void main(String[] args) throws Exception {
String location = SimpleIOC.class.getClassLoader().getResource("ioc.xml").getFile();
SimpleIOC bf = new SimpleIOC(location);
Wheel wheel = (Wheel) bf.getBean("wheel");
// DazhongCar car = (DazhongCar) bf.getBean("car");
//原因:不能用接口的实现类(DazhongCar)来转换Proxy的实现类,它们是同级,应该用共同的接口来转换。
Car car = (Car) bf.getBean("daZhongCar");
car.driver();
}
}
现阶段存在的主要问题:
- 依赖类必须在配置文件中先被声明,保证先被初始化。需要修改读取配置文件的部分,先读取封装好再来统一初始化。
- 不解决循环依赖,这个可能还得啃一啃官方源码才能实现吧。
参考:自己动手实现的 Spring IOC 和 AOP - 上篇