spring中IoC和AOP的实现

6.2 spring IoC

IoC容器是Spring的核心。容器从配置文件中读取需要创建哪些对象,并在创建后按照要求把它们进行装配,通过这样的方法达到业务代码解耦的目的。不仅如此,spring还负责管理这些对象从创建到销毁的整个生命周期。在代码实现中,我们通常把这些对象叫做SpringBean,通过结构复杂的Bean工厂来完成它们的创建。

6.2.1 BeanFactory

BeanFactory是典型的工厂模式(工厂模式,请见9.3)设计,继承结构中的子类表示在父类的基础上增加的功能,比如DefaultListableBeanFactory就具有两个父类的可配置、可列表、可自动装配的功能。实际上除了DefaultListableBeanFactory其他类都是抽象类,DefaultListableBeanFactory是唯一可直接创建的类。

那么BeanFactory有哪些功能呢?我们来看一下它的方法:

public interface BeanFactory {    
     
     //对FactoryBean的转义定义          
     String FACTORY_BEAN_PREFIX = "&"; 
        
     //根据bean的名字,获取在IOC容器中得到bean实例    
     Object getBean(String name) throws BeansException;    
   
    //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。    
     Object getBean(String name, Class requiredType) throws BeansException;    
    
    //提供对bean的检索,看看是否在IOC容器有这个名字的bean    
     boolean containsBean(String name);    
    
    //根据bean名字得到bean实例,并同时判断这个bean是不是单例    
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;    
    
    //得到bean实例的Class类型    
    Class getType(String name) throws NoSuchBeanDefinitionException;    
    
    //得到bean的别名,如果根据别名检索,那么其原名也会被检索出来    
   String[] getAliases(String name);    
    
 }

实际上BeanFactory中只定义了一个SpringBean的基本行为,主要的功能是操作一个bean对象。

6.2.2 ApplicationContext

ApplicationContext和BeanFactory类似,也是一个对Bean对象进行行为操作的类,但是ApplicationContext集成了很多新的功能,相比较BeanFactory而言更加强大,新功能有但是不限于:

  1. 支持信息源,可以实现国际化
  2. 访问资源
  3. 支持应用事件

6.2.3 BeanDefinition

说了两种对Bean对象进行操作的类,那么Bean对象是如何创建的呢?在Spring中,BeanDefinition类用来表示一个Bean对象的实体。

6.2.4 BeanDefinitionReader

有了BeanDefinition,也有了操作BeanDefinition的ApplicationContext,现在只差进行创建的类了,这个类就是BeanDefinitionReader。

6.2.5 BeanDefinitionRegistry

BeanDefinitionRegistry是一个注册中心,所有创建的BeanDefinition都会在注册中心记录,BeanFactory和ApplicationContext的具体实现类都继承了这个接口,所有都具有被注册的属性。

6.2.6 IoC容器创建Bean流程

先由BeanDefinitionReader的具体实现类,比如PropertiesBeanDefinitionReader、XmlBeanDefinitionReader去扫描需要进行配置的Bean封装成BeanDefinition对象,再由ApplicationContext对其进行操作注入。大体思路有了,实际上真实的spring操作过程与此有一些不同之处:

  1. BeanDefinitionReader先扫描所有文件,找出需要注入的Bean并且将其封装为BeanDefinition,封装后注入BeanDefinitionRegistry的某一具体实现类。
  2. spring内部采用惰性加载,如果一个BeanDefinition,没有被getBean方法调用那么不会进行加载,当被调用时才进行注入。

6.3 spring AOP

Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

6.3.1 AspectJ

AspectJ是一种AOP的编程工具,通过一定格式的代码书写可以让JVM在编译时动态的创建代理类,并在每个方法前后增加AOP的代码,原理上来讲是一种静态代理。

public aspect LogAspect{
    pointcut logPointcut():execution(void HelloService.hello());
    after():logPointcut(){
         System.out.println("logger"); 
    }
}

实际上spring并没有集成AspectJ工具,只是采用了类似AspectJ的书写方式来完成AOP的实现,内部采用的方法是JDK的动态代理。

6.3.2 spring JDK动态代理

6.3.2.1 applicationContext.xml配置

在applicationContext.xml中配置下面一句

<aop:aspectj-autoproxy />

6.3.2.2 注解类型

  1. Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可
  2. AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值
  3. AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名来访问目标方法中所抛出的异常对象
  4. After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式
  5. Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint
@Component
@Aspect
public class Operator {
    
    @Pointcut("execution(* com.aijava.springcode.service..*.*(..))")
    public void pointCut(){}
    
    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint){
        System.out.println("AOP Before Advice...");
    }
    
    @After("pointCut()")
    public void doAfter(JoinPoint joinPoint){
        System.out.println("AOP After Advice...");
    }
    
    @AfterReturning(pointcut="pointCut()",returning="returnVal")
    public void afterReturn(JoinPoint joinPoint,Object returnVal){
        System.out.println("AOP AfterReturning Advice:" + returnVal);
    }
    
    @AfterThrowing(pointcut="pointCut()",throwing="error")
    public void afterThrowing(JoinPoint joinPoint,Throwable error){
        System.out.println("AOP AfterThrowing Advice..." + error);
        System.out.println("AfterThrowing...");
    }
    
    @Around("pointCut()")
    public void around(ProceedingJoinPoint pjp){
        System.out.println("AOP Aronud before...");
        try {
            pjp.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("AOP Aronud after...");
    }
    
}

6.3.3 CGLIB

除了JDK自带的动态代理法,spring还有一种更加方便的AOP实现方法就是CGLIB(Code Generation Library)。

JDK代理要求被代理的类必须实现接口,或者采用相应的注解,这种方法有很强的局限性。而CGLIB动态代理则没有此类强制性要求。简单的说,CGLIB会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。在CGLIB底层,其实是借助了ASM这个非常强大的Java字节码生成框架。需要注意的是CGlib可以传入接口也可以传入普通的类,接口使用实现的方式,普通类使用会使用继承的方式生成代理类,但是如果传入的类是final修饰,方法是static或private修饰的时候CGLIB无法进行代理。

猜你喜欢

转载自blog.csdn.net/QuinnNorris/article/details/81382636