什么是IOC
在传统项目中,类A要使用类B的某个方法f,这时候一般是这么实现:
1 2 3 4 5 6
| public class A { public void test() { B b = new B(); b.f(); } }
|
这时,B的创建是有A来自己完成的,我们可以说A拥有B的创建、管理权限。

但是这种情况下,A和B就是强关联的,我们希望A和B是松耦合的状态,显然直接new肯定是不行的。
所以IOC(控制反转)主要就是描述了一种将对象的创建管理权限交给IOC容器管理,自己不负责创建管理的思想。

什么是DI
DI:依赖注入,其实它和IOC描述的是同⼀件事情,只不过角度不同。
上面我们从对象的角度描述了什么是IOC,如果我们把角度切换到IOC容器时,就会发现ioc容器主要完成的事情,就是把A需要的B,进行注入,这个过程就叫依赖注入。
自定义实现IOC
基于上面的解释,要实现一个类似SpringIOC的ioc容器,可以分成几个步骤(基于注解的模式):
- 扫描指定包下所有类(或者带指定注解的类);
- 进行类的实例化,生成对象;
- 对象的属性是否需要依赖注入,如果需要则注入(通过注解判断);
- 最后将对象存放到容器中,等待使用;
- 测试是否成功;
针对上面的步骤,我们进行一步一步的实现。
首先自定义了一个注解,用于指定需要扫描:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| .......
@Target(value = ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Service {
String value() default "";
}
.......
@Target(value = ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowire {
}
|
然后声明一个AnnotationApplication类,作为启动时用来加载需要加载类的入口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class AnnotationApplication {
private String packageName;
private static Map<String, BeanDefinition> bdMap = new HashMap<>(); public AnnotationApplication(String packageName) throws Exception { this.packageName = packageName; initBean(); }
public void initBean() throws Exception { ClassUtil.getClasses(packageName, bdMap); for(String beanId : bdMap.keySet()){ createBean(bdMap.get(beanId)); } System.out.println("bean加载完成!"); } }
|
其中Bean定义使用的是自定义的BeanDefinition,并非是Spring的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class BeanDefinition {
private String beanId;
private Class<?> clazz;
private Class<?>[] interfaces;
public String getBeanId() { return beanId; }
public void setBeanId(String beanId) { this.beanId = beanId; }
public Class<?> getClazz() { return clazz; }
public void setClazz(Class<?> clazz) { this.clazz = clazz; }
public Class<?>[] getInterfaces() { return interfaces; }
public void setInterfaces(Class<?>[] interfaces) { this.interfaces = interfaces; } }
|
在其中定义了扫描的包路径packageName,通过构造方法传入,然后就会调用initBean()进行对象初始化加载,里面通过一个工具类ClassUtil将指定包下所有包含自定义的@Service注解的类,进行加载,最终生成一个BeanDefinition,并根据name或者类名的首字母小写作为key进行存储到bdMap。
然后对扫描到的类进行逐个的实例化,调用createBean生成对象实例,实现过程中判断是否是接口,以及注解中是否自定义了beanName。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| private Object createBean(BeanDefinition bd) throws Exception { if (bd.getClazz().isInterface()) { return initInterface(bd.getClazz()); }
String beanId = bd.getClazz().getAnnotation(Service.class).value(); if (null != beanId && !"".equals(beanId) && 0 < beanId.length()) { bd.setBeanId(beanId); } return doCreateBean(bd); }
private Object initInterface(Class clazz) throws Exception { for(BeanDefinition bd : bdMap.values()){ Class<?>[] interfaces = bd.getInterfaces(); if (null != interfaces && 0 < interfaces.length) { for (Class<?> inter : interfaces) { if (clazz == inter) { return createBean(bd); } } } } return null; }
|
最终所有的bean都会调用doCreateBean方法,进行具体的bean创建过程。
创建之前,先判断缓存中是否有,有的话表示已经创建过了,直接获取就行;
如果没有,则进行实例化等一系列操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| private static Map<String, Object> singletonBeanMap = new ConcurrentHashMap<>();
private static Map<String, Object> earlySingletonObjects = new HashMap<>();
private static Map<String, Boolean> beanCreateStatus = new HashMap<>(); private Object doCreateBean(BeanDefinition bd) throws Exception { String beanId = bd.getBeanId(); Object singletonObj = singletonBeanMap.get(beanId); if (singletonObj == null && isBeanInCreating(beanId)) { singletonObj = this.earlySingletonObjects.get(beanId); } if (null != singletonObj) { return singletonObj; } beanCreateStatus.put(beanId, true); Object obj = bd.getClazz().newInstance(); earlySingletonObjects.put(beanId, obj); initBeanWire(obj); obj = createTransactionObj(obj); singletonBeanMap.put(beanId, obj); earlySingletonObjects.remove(beanId); beanCreateStatus.remove(beanId); return obj; }
private boolean isBeanInCreating(String beanId){ Boolean flag = beanCreateStatus.get(beanId); if (null != flag) { return flag; } return false; }
|
创建的时候,先进性状态标记,防止多个创建同时发生;并且我们使用二级缓存,将实例化完成的对象进行存放,防止循环依赖的情况。
实例化之后,就是进行属性注入,调用initBeanWire方法,判断是否有自定义的注入注解例如@Autowire,进行逐个的属性注入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private void initBeanWire(Object o) throws Exception { Class clazz = o.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { Annotation[] annotations = field.getAnnotations(); for (Annotation ann : annotations) { if (ann instanceof Autowire){ Class filedType = (Class) field.getGenericType(); String beanId = ClassUtil.getBeanIdByClass(filedType); Object bean = createBean(bdMap.get(beanId)); field.setAccessible(true); field.set(o, bean); System.out.println("属性注入成功"); } } } }
|
最终会重新调用createBean去生成依赖的对象,如果对象存在则直接缓存获取,没有的时候,就会去创建。
循环依赖
循环依赖指的是:A里依赖B,B里同时也依赖A;当创建A的时候,属性注入B,发现B还不存在,则会去创建B,B创建的时候发现依赖A,但是A在创建中也没有创建完成,最终产生错误,这就是循环依赖。
上面我们自定义的IOC是怎么解决这个问题呢?
这里我们是进行了一个简单的解决,就是在A实例化(bd.getClazz().newInstance())完成后,将结果放入一个二级缓存private static Map<String, Object> earlySingletonObjects = new HashMap<>();,再去执行属性B的注入,然后当实例化B的时候,发现依赖A,这时直接从二级缓存中获取,打破循环依赖,完成B的创建,最终A的Bean也完成创建。
为什么要用二级缓存呢?
首先是将最终的对象与中间对象进行区别,同时因为下面我们要进行AOP的一些操作,会进行代理对象的生成,所以使用一个简单的二级缓存。
实际上,Spring解决循环依赖借助的是三级缓存,具体见Spring相关笔记中的循环依赖问题。
什么是AOP
了解AOP之前,首先我们需要知道常用的OOP,也就是面向对象编程。
在OOP中,一切都是对象,它的特性就是封装、继承、多态,所以会进行一些父类的抽取,最终会形成一个垂直的继承体系。

OOP编程思想可以解决⼤多数的代码重复问题,但是还是有一些情况解决不了。比如判断方法执行时间、在方法执行前后进行日志记录等,这些操作是与业务代码无关的代码,而且多个方法都出现这样的情况,通过OOP的思想已经无法向上抽取,只能在每个方法中进行重复编写。
总的来说,这些代码存在以下问题:
- 代码重复;
- 与业务无关,但是和业务逻辑代码混合在一起,维护不方便;
这时就产生了AOP的思想,即面向切面编程。
将这些与业务无关的逻辑(称为横切逻辑)进行拆分提出,形成单独的处理类,最终在具体方法执行时,自动加在执行的前或后,完成切面逻辑与业务逻辑的融合,达到不改变业务类,却可以随时更换切面逻辑的效果。
自定义实现AOP
这里我们通过实现事务管理方式,实现自定义的AOP。
实现步骤:
1)自定义一个事务注解@Transactional;
2)把注解声明在类或方法上;
3)创建Bean的时候,进行事务判断,最终生成代理类;
第一步和第二步比较简单,代码就不再展示,当完成方法上的注解添加之后,再去修改AnnotationApplication的创建Bean。
上面的代码中doCreateBean里面调用的createTransactionObj(obj);就是去声明事务注解的加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| private Object createTransactionObj(Object obj) throws Exception { Class<?> clazz = obj.getClass(); boolean proxyFlag = false; Transactional clazzAnn = clazz.getAnnotation(Transactional.class); List<Method> methodList = new ArrayList<>(); if (null != clazzAnn) { proxyFlag = true; } else { Method[] methods = clazz.getMethods(); for (Method method : methods) { Transactional methodAnn = method.getAnnotation(Transactional.class); if (null != methodAnn) { methodList.add(method); proxyFlag = true; } } } if (!proxyFlag) { return obj; } else { String beanId = ClassUtil.getBeanIdByClass(ProxyFactory.class); ProxyFactory proxyFactory = (ProxyFactory) createBean(bdMap.get(beanId)); return proxyFactory.getProxyObj(obj, methodList); } }
|
最终将使用了自定义的@Transactional注解的类或者方法,通过代理工厂ProxyFactory生产一个代理对象;
1 2 3 4 5 6 7
| public Object getProxyObj(Object obj, List<Method> methodList) { Class<?>[] interfaces = obj.getClass().getInterfaces(); if (null == interfaces || 0 == interfaces.length) { return getCglibProxy(obj, methodList); } return getJdkProxy(obj, methodList); }
|
最终根据是否实现接口,来判断使用哪种代理方式。而在其中的invoke方法中,完成事务的处理;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
public Object getJdkProxy(Object obj, List<Method> methodList) { return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; boolean proxyFlag = false; if (null != methodList && 0 < methodList.size()) { for (Method proxyMethod : methodList) { if (method.getName().equals(proxyMethod.getName())) { proxyFlag = true; } } } else { proxyFlag = true; } try{ if (proxyFlag) { System.out.println("使用JDK动态代理进行事务控制"); transactionManager.beginTransaction(); } result = method.invoke(obj, args); if (proxyFlag) { transactionManager.commit(); } }catch (Exception e) { e.printStackTrace(); if (proxyFlag) { transactionManager.rollback(); } } return result; } });
}
|
最终将返回的代理对象存入缓存中,当使用到相应的方法时,就会使用代理对象先进行代理逻辑执行,完成事务控制的输出,然后再执行业务逻辑代码。
到此,自定义的AOP也就完成了。 其中,我们默认了代理逻辑等,后续可以将此部分改成从配置中获取,进一步完善。
自测
首先需要增加用户相关dao层、service层,此处不展示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class ITest {
@Test public void test() throws Exception { AnnotationApplication annApp = new AnnotationApplication("com.liufujun.edu"); UserServiceImpl userService = (UserService) annApp.getBean(UserServiceImpl.class); userService.create("22222222","33333333", 100); System.out.println("创建完成!"); }
@Test public void testException() throws Exception { AnnotationApplication annApp = new AnnotationApplication("com.liufujun.edu"); UserService userService = (UserService) annApp.getBean(UserServiceImpl.class); userService.createWithException("22222222","33333333", 100); System.out.println("创建执行完成!"); }
@Test public void testProxy() throws Exception { AnnotationApplication annApp = new AnnotationApplication("com.liufujun.edu"); UserProxyService userService = (UserProxyService) annApp.getBean(UserProxyService.class); userService.createWithException("22222222","33333333", 100); System.out.println("创建完成!"); }
}
|
最终可以正常获取到指定的对象,正确的执行对应的方法,并且输出事务aop逻辑日志,验证成功!