最简单的IOC容器只需要4步即可实现
- 加载xml配置文件,遍历其中的标签
- 获取标签中的id和class属性,加载class属性对应的类,并创建bean
- 遍历标签中的标签,获取属性值,并将属性值填充到bean中
- 将bean注册到bean容器中
SimpleIOC:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class SimpleIOC {
private Map<String,Object> 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("没有叫"+name+"的bean");
}
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();
//遍历<bean>标签
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();
//遍历<property>标签
NodeList propertyNodes = ele.getElementsByTagName("property");
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);
}else {
String ref = propertyElement.getAttribute("ref");
if (ref == null || ref.length() == 0){
throw new IllegalArgumentException("ref 参数错误");
}
//将引用填充到相关字段中
declaredField.set(bean,getBean(ref));
}
//将bean注册到bean容器中
registerBean(id,bean);
}
}
}
}
}
private void registerBean(String id,Object bean){
beanMap.put(id,bean);
}
}
Car:
package com.sc.domain;
import java.io.Serializable;
public class Car implements Serializable {
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;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", length='" + length + '\'' +
", width='" + width + '\'' +
", height='" + height + '\'' +
", wheel=" + wheel +
'}';
}
}
Wheel:
package com.sc.domain;
public class Wheel {
private String brand;
private String specification;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getSpecification() {
return specification;
}
public void setSpecification(String specification) {
this.specification = specification;
}
@Override
public String toString() {
return "Wheel{" +
"brand='" + brand + '\'' +
", specification='" + specification + '\'' +
'}';
}
}
ioc.xml
<beans>
<bean id="wheel" class="com.sc.domain.Wheel">
<property name="brand" value="Michelin"></property>
<property name="specification" value="265/60 R18"/>
</bean>
<bean id="car" class="com.sc.domain.Car">
<property name="name" value="benchi G 500"/>
<property name="length" value="4717mm"/>
<property name="width" value="1949mm"/>
<property name="height" value="1855mm"/>
<property name="wheel" ref="wheel"/>
</bean>
</beans>
main:
public class SimpleIOCTest {
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");
System.out.println(wheel);
Car car = (Car) bf.getBean("car");
System.out.println(car);
}
}
结果:
Wheel{brand='Michelin', specification='265/60 R18'}
Car{name='benchi G 500', length='4717mm', width='1949mm', height='1855mm', wheel=Wheel{brand='Michelin', specification='265/60 R18'}}
简单的AOP实现:
五种类型的通知
- Before:在目标法执行前执行通知
- After:在目标法执行后执行通知,不关系返回值是什么
- After-returning:在目标方法执行后,执行通知
- After-throwing:目标方法抛出异常后执行通知
- Around:目标法被通知包裹,通知在目标方法执行前后都会被调用
切点:在何处通知,通过匹配规则找到连接点,AOP会在这些连接点上织入通知
切面:切面包含了 通知 和 切点 ,在何时何处执行切面逻辑
此处我们通过动态代理实现AOP,步骤如下:
- 定义一个包含切面逻辑的对象logMethodInvocation
- 定义一个Advice对象(实现了InvocationHandler接口),并将上面的logMethodInvocation和目标对象传入
- 将上面的Advice对象和目标对象传给JDK动态代理方法,为目标对象生成代理
MethodInvocation:
/**
* 他的实现类包含切面逻辑
*/
public interface MethodInvocation {
void invoke();
}
Advice:
/**
* 继承了InvocationHandler接口
* 每个代理类的调用处理程序都必须实现InvocationHandler接口
* 相当于所有通知类的父类
*/
public interface Advice extends InvocationHandler {
}
BeforAdvice:
/**
* 实现了Advice接口,是一个前置通知
*/
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);
}
}
SimpleAOP:
import java.lang.reflect.Proxy;
/**
* 生成代理类
*/
public class SimpleAOP {
public static Object getProxy(Object bean,Advice advice){
return Proxy.newProxyInstance(SimpleAOP.class.getClassLoader(),
bean.getClass().getInterfaces(),advice);
}
}
HelloService接口:
/**
* 目标对象接口
*/
public interface HelloService {
void sayHelloWorld();
}
HelloServiceImpl:
/**
* 接口实现类
*/
public class HelloServiceImpl implements HelloService{
@Override
public void sayHelloWorld() {
System.out.println("hello world aop!");
}
}
SimpleAOPTest:
/**
* aop测试类
*/
public class SimpleAOPTest {
public static void main(String[] args) {
//1.创建一个MethodInvocation实现类
MethodInvocation logTask = ()-> System.out.println("log task start");
//目标对象
HelloService helloServiceImpl = new HelloServiceImpl();
//2.创建一个Advice
Advice beforeAdvice = new BeforeAdvice(helloServiceImpl,logTask);
//3.为目标对象生成代理
HelloService helloServiceImplProxy = (HelloService)
SimpleAOP.getProxy(helloServiceImpl,beforeAdvice);
helloServiceImplProxy.sayHelloWorld();
}
}
最后的输出:
log task start
hello world aop!