AOP思想的实现方法一般是代理模式。jdk只支持接口的代理,而对于类的代理,Spring支持了CGLIB,AspectJ动态代理。
IOC的实现原理是反射。
如果我们要做一个简单的IOC容器。
首先实现简单的四步:
1.扫描xml配置文件。
2.遍历所有的bean节点。读取id和class属性
3.遍历bean节点下每个property节点的name和value或ref值。将值注入到属性中
4.将加载的bean注入到容器中
为了实现上述功能,创建如下几个类:
springIOC ioc的实现类
springIOCTest ioc测试类
car 汽车实体类
wheel 车轮实体类
ioc.xml ioc配置文件
springIOC类:
package SpringIOC; import java.io.FileInputStream; import java.lang.reflect.Field; 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 SpringIOC { private Map<String, Object> map = new HashMap<>(); public SpringIOC(String xmlName) throws Exception{ loadbean(xmlName); } public Object getbean(String beanName){ Object bean = map.get(beanName); if(bean == null){ throw new IllegalArgumentException(); } return bean; } private void registerBean(String id, Object bean) { map.put(id, bean); } public void loadbean(String xmlName) throws Exception{ FileInputStream fileInputStream = new FileInputStream(xmlName); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder newDocumentBuilder = factory.newDocumentBuilder(); Document Document = newDocumentBuilder.parse(fileInputStream); Element root = Document.getDocumentElement(); NodeList childNodes = root.getChildNodes(); for(int i =0;i<childNodes.getLength();i++){ Node node = childNodes.item(i); if(node instanceof Element){ Element element = (Element)node; String id = element.getAttribute("id"); String className = element.getAttribute("class"); Class<?> beanClass = null; try { beanClass = Class.forName(className); } catch (Exception e) { e.printStackTrace(); return; } Object bean = beanClass.newInstance(); //解析property属性值,并注入 NodeList propertyList = element.getElementsByTagName("property"); for(int j=0;j<propertyList.getLength();j++){ Node propertyItem = propertyList.item(j); if(propertyItem instanceof Element){ Element property = (Element)propertyItem; String name = property.getAttribute("name"); String value = property.getAttribute("value"); //利用反射机制将类的内部属性变为可访问的 Field filed = bean.getClass().getDeclaredField(name); filed.setAccessible(true);if(value != null && value.length()>0){ filed.set(bean, value); }else{ String ref = property.getAttribute("ref"); if (ref == null || ref.length() == 0) { throw new IllegalArgumentException("ref config error"); } filed.set(bean, getbean(ref)); } } } registerBean(id, bean); } } } }
由此可知IOC的实现原理是反射。
springIOCtext类:
package SpringIOC; public class SpringIOCTest { public static void main(String[] args) throws Exception { SpringIOC springIOC = new SpringIOC("C:/file/Workspaces/StringTest/bin/SpringIOC/ioc.xml"); Car car = (Car)springIOC.getbean("car"); Wheel wheel = (Wheel)springIOC.getbean("wheel"); System.out.println(car); System.out.println(wheel); } }
实体类和ioc.xml:
package SpringIOC; public class Car { private String Carbrand; private Wheel wheel; public String getCarbrand() { return Carbrand; } public void setCarbrand(String carbrand) { Carbrand = carbrand; } public Wheel getWheel() { return wheel; } public void setWheel(Wheel wheel) { this.wheel = wheel; } @Override public String toString() { return "Car [Carbrand=" + Carbrand + ", wheel=" + wheel + "]"; } }
package SpringIOC; public class Wheel { private String wheelBrand; private String width; private String height; public String getWheelBrand() { return wheelBrand; } public void setWheelBrand(String wheelBrand) { this.wheelBrand = wheelBrand; } 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; } @Override public String toString() { return "Wheel [wheelBrand=" + wheelBrand + ", width=" + width + ", height=" + height + "]"; } }
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="wheel" class="SpringIOC.Wheel"> <property name="wheelBrand" value="米其林"> </property> <property name="width" value="50"> </property> <property name="height" value="50"> </property> </bean> <bean id="car" class="SpringIOC.Car"> <property name="Carbrand" value="奔驰"> </property> <property name="wheel" ref="wheel"> </property> </bean> </beans>
这里就简单的IOC容器的实现,运行结果:
Car [Carbrand=奔驰, wheel=Wheel [wheelBrand=米其林, width=50, height=50]]
Wheel [wheelBrand=米其林, width=50, height=50]
但是最简陋的IOC容器,随便考虑一下就还有非常多需要改进的地方还有非常的多
AOP的简单实现
AOP思想的实现原理是代理模式,简单AOP的容器先使用JDK中proxy类生成代理类
通知
通知有五种类型:
1.前置通知 在目标方法执行前执行
2.后置通知 在目标方法执行后执行,此时无关返回
3.返回通知 在目标方法执行后执行
4.异常通知 在目标方法抛出异常后执行通知
5.环绕通知 目标方法被通知包裹,通知在方法执行前后都会执行
切点
如果说通知定义了在何时执行通知,那么切点就定义了在何处执行通知。所以切点的作用就是通过匹配规则查找合适的连接点(Joinpoint),AOP 会在这些连接点上织入通知。
为了实现简单AOP,创建以下类
MethodInvocation 实现了切面逻辑
Advice 继承了invocationHandler接口
BeforeAdvice 实现了Advice接口、
SpringAop 生成代理类
SpringAopTest 测试类
HelloWord 目标方法接口
HelloWordImpl 目标方法实现类
MethodInvocation:
public interface MethodInvocation { void invoke(); }
Advice:
public interface Advice extends InvocationHandler {}
beforeAdvice:
public class BeforeAdvice implements Advice { private Object bean; private MethodInvocation methodInvocation; public BeforeAdvice(Object bean, MethodInvocation methodInvocation) { this.bean = bean; this.methodInvocation = methodInvocation; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在目标方法执行前调用 methodInvocation.invoke(); return method.invoke(bean, args);//该方法表示执行被代理类原本的逻辑 // 若在目标方法执行后调用,只需要将逻辑写在method.invoke之后 } }
SpringAop:
public class SimpleAOP { public static Object getProxy(Object bean, Advice advice) { return Proxy.newProxyInstance(SimpleAOP.class.getClassLoader(), bean.getClass().getInterfaces(), advice); } }
SpringAopTest:
public class SimpleAOPTest { @Test public void getProxy() throws Exception { // 1. 创建一个 MethodInvocation 实现类 MethodInvocation logTask = () -> System.out.println("log task start"); HelloServiceImpl helloServiceImpl = new HelloServiceImpl(); // 2. 创建一个 Advice Advice beforeAdvice = new BeforeAdvice(helloServiceImpl, logTask); // 3. 为目标对象生成代理 HelloService helloServiceImplProxy = (HelloService) SimpleAOP.getProxy(helloServiceImpl,beforeAdvice); helloServiceImplProxy.sayHelloWorld(); } }
代理类及其实现:
public interface HelloService { void sayHelloWorld(); } public class HelloServiceImpl implements HelloService { @Override public void sayHelloWorld() { System.out.println("hello world!"); } }