Spring

2018-11-09  本文已影响0人  Goooooooooooal

AOP

Java提倡OOP,面向对象编程。OOP三大特性包括封装、继承和多态。当多个类需要相同的业务时,则创建1个父类,通过让子类继承父类的方式,来消除重复代码

OOP是纵向的继承,AOP是面向切面编程,相比于OOP,AOP是横向的抽取。AOP是OOP的补充

在一个方法中,与业务无关的代码称为横切逻辑,例如性能检测代码、日志代码都是横切逻辑。横切逻辑在业务代码之前或之后,与业务代码紧耦合。这种横切逻辑不利于代码的重构和优化,也不利于修改bug

AOP将横切逻辑和业务代码分离开来,将重复的横切逻辑封装成切面,再注入到业务代码中,使程序员更关注业务代码的开发。

AOP支持动态代理和CGLIB代理,默认使用动态代理

  1. 动态代理要求被代理类实现接口,使用java.lang.reflect的Proxy类和InvocationHandler接口

InvocationHandler持有被代理类的对象,在其invoke()中,通过反射机制,调用被代理类对象的被代理方法

通过Proxy的静态方法newProxyInstance()获得代理类,最终在运行时,动态生成的代理类extends Proxy implements 被代理类实现的接口,同时它还持有InvocationHandler对象

当执行代理类方法时,会调用它持有的InvocationHandler对象的invoke(),而该方法又使用反射机制调用被代理类的方法。这就是动态代理,在运行时生成代理对象,并且在被代理类方法的前后加入自定义业务逻辑

所以,动态代理的本质还是去调用被代理类的方法,只不过在调用前后,要执行代理类定义的横切逻辑

  1. CGLIB代理
    动态代理只能对实现接口的类进行代理。CGLIB代理使用字节码处理框架ASM生成代理类的字节码,根据字节码生成代理类对象,代理类是被代理类的子类,覆盖了被代理类的方法,来对它进行增强。因为采用继承,CGLIB无法代理final类,也不会拦截被代理类的final方法和static方法

CGLib使用Enhancer生成代理类对象,需要使用setSuper()设置代理类的父类,也就是被代理类;使用setCallback()设置回调被代理类方法,是1个实现MethodInterceptor接口的实现类,在该类的intercept()调用被代理类的方法

使用AOP

AOP在动态代理和CGLib代理的基础上

  1. 使用@PointCut定义切点, 在切点表达式中指定在哪个类,哪个方法上注入横切逻辑
  2. 使用增强Advice,描述横切逻辑的具体织入点,包括在方法执行前@Before,方法执行后@After,环绕@Around,抛出异常后@AfterThrowing,方法返回后@AfterReturning
  3. 使用切面@Aspect,将切点和增强组合起来,在利用代理切面织入到被代理类

IOC

JAVA程序中,1个业务逻辑通常由多个对象来完成,1个对象在使用其依赖对象时,需要使用new来创建其依赖对象,再访问它的属性或者调用它的方法。这种方式,使2个对象紧耦合在一起,不利于代码的重构、优化和修改

Spring使用Ioc容器来存放所有用到的对象,Ioc即Inverse of Control,控制反转。对象的控制权反转了,之前由对象来创建其依赖对象,现在由Spring统一创建和维护,只有在使用的时候,才注入依赖的对象,所以也称为依赖注入

  1. 一般使用@Autowired注解来注入依赖的对象,这个注解默认以byType的形式注入对象,将Ioc容器中该类型的Bean注入。byName需要额外加上@Qualifier指定Bean的name

  2. Spring默认创建单例的Bean,容器中1个类只有1个对象,多次使用getBean()获取Bean,会得到同1个对象

  3. Ioc容器指的是BeanFactory,BeanFactory使用反射来实例化Bean,建立Bean的依赖关系,但一般不使用BeanFactory,使用应用上下文ApplicationContext。ApplicationContext建立在BeanFactory基础之上,
    继承了BeanFactory的子接口ListableBeanFactory,在BeanFactory基础上添加了额外的功能

  4. BeanFactory启动时,不会实例化Bean,第一次getBean()时才会实例化Bean,但是BeanFactory会缓存单例Bean
    ApplicationContext启动时,会实例化所有单例Bean,放入缓存。缓存是1个HashMap,key为Bean的name,value为Bean对象。AapplicationContext在启动时实例化所有单例Bean,虽然浪费一点时间,但又2个好处
    (1)提前实例化Bean,让潜在的问题提前暴露
    (2)实例化后放入缓存,之后getBean()从缓存中获取

上一篇下一篇

猜你喜欢

热点阅读