Spring

作者: Goooooooooooal | 来源:发表于2018-11-09 14:51 被阅读0次

    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()从缓存中获取

    相关文章

      网友评论

          本文标题:Spring

          本文链接:https://www.haomeiwen.com/subject/rnwnxqtx.html