spring注解版

Posted cxyyh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring注解版相关的知识,希望对你有一定的参考价值。

第一.spring框架快速入门

1.1什么是spring 框架

Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Control,控制反转)

和 AOP(Aspect Oriented Programming,面向切面编程)。

理念:每个bean与bean之间的关系统一交给SpringIOC容器管理

New UserService(); 扫包、注解形式注入 使用容器帮助我们创建对象 底层大量反射机制。

1.2spring框架的体系结构

1、Spring Core:主要组件是BeanFactory,创建JavaBean的工厂,使用控制反转(IOC) 模式  将应用程序的配置和依赖性规范与实际的应用程序代码分开。

2、Spring AOP:集成了面向切面的编程功能(AOP把一个业务流程分成几部分,例如权限检查、业务处理、日志记录,

 每个部分单独处理,然后把它们组装成完整的业务流程。每个部分被称为切面),可以将声明性事物管理集成到应用程序中。

3、Spring Cntext:一个核心配置文件,为Spring框架提供上下文信息。

4、Spring Do:Spring操作数据库的模块。

5、Spring ORM:Spring集成了各种orm(object relationship mapping 对象关系映射)框架的模块,集成mybatis

6、Spring Web集成各种优秀的web层框架的模块(Struts、Springmvc)

7、Spring web MVC:Spring web层框架

1.3快速构建spring环境

1.maven依赖信息

 <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
        </dependency>
    </dependencies>

2.实体类

public class UserEntity 
    private Integer userId;
    private String userName;

    public Integer getUserId() 
        return userId;
    

    public UserEntity(String userName,Integer userId)
        this.userId = userId;
        this.userName = userName;
    
    public void setUserId(Integer userId) 
        this.userId = userId;
    

    public String getUserName() 
        return userName;
    

    public void setUserName(String userName) 
        this.userName = userName;
    

    @Override
    public String toString() 
        return "UserEntity" + "userId=" + userId + ", userName=‘" + userName + ‘\\‘‘ + ‘‘;
    

3.xml环境搭配

application.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="userEntity" class="com.yehui.demo01.entity.UserEntity">
        <property name="userName" value="yehui"/>
        <property name="userId" value="10"/>
    </bean>
</beans>

4.spring启动类

      //1.读取spring配置文件,创建IOC容器
      ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("application.xml");
      //2.从SpringIoc容器获取userEntity
        UserEntity userEntity = context.getBean("userEntity", UserEntity.class);
        System.out.println("xml读取:"+userEntity);

5.注解方式搭建

1.@Configuration

  使用Configuration 配置容器
//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
public class MainConfig 

    @Bean  //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id 主要作用是导入外包jar包
    public UserEntity userEntity()
        return new UserEntity("name",32432);
    
使用注解形式加载ioc
public class TestMain 
    public static void main(String[] args) 

        AnnotationConfigApplicationContext
                context = new AnnotationConfigApplicationContext(MainConfig.class);
        UserEntity bean = context.getBean(UserEntity.class);
        System.out.println(bean);
    

2.@ComponentScan用法

扫包下注入springIOC容器中

配置类

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
@ComponentScan("com.yehui.demo01")
public class MainConfig 

    //@ComponentScan  value:指定要扫描的包

    @Bean  //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    public UserEntity userEntity()
        return new UserEntity("name",32432);
    

分别在service、controller、dao包下面建立类,并打上对于的注解,例如下面

技术图片

test类
public class TestMain 
    public static void main(String[] args) 

        AnnotationConfigApplicationContext
                context = new AnnotationConfigApplicationContext(MainConfig.class);
        //得到所有包下的所有注解类
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) 
            System.out.println(beanDefinitionName);
        
    
效果:

技术图片

includeFilters

FilterType 有四种类型

ANNOTATION:注解类型

ASSIGNABLE_TYPE:ANNOTATION:指定的类型

ASPECTJ:按照Aspectj的表达式,基本上不会用到

REGEX:按照正则表达式

CUSTOM:自定义规则

 config类
//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
@ComponentScan(value = "com.yehui.demo01",
      includeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM,classes =
              MyTypeFilter.class),useDefaultFilters = false
      /  includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,
        classes = Controller.class),useDefaultFilters = false/
        /excludeFilters =
               @ComponentScan.Filter(
                       type = FilterType.ANNOTATION,
                       classes = Controller.class)
        /)
public class MainConfig 

    //@ComponentScan  value:指定要扫描的包
    //@ComponentScan  value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则

    @Bean  //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    public UserEntity userEntity()
        return new UserEntity("name",32432);
    
 自定义过滤器
public class MyTypeFilter implements TypeFilter 

    /
      metadataReader:读取到的当前正在扫描的类的信息
      metadataReaderFactory:可以获取到其他任何类信息的
     /
    @Override
    public boolean match(MetadataReader metadataReader,
                         MetadataReaderFactory metadataReaderFactory) throws IOException 
        // TODO Auto-generated method stub
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();

        String className = classMetadata.getClassName();
        System.out.println("--->"+className);
        if(className.contains("er"))
            return true;
        
        return false;
    

 3.@Scope

默认情况Spring容器是单例的

singleton单例模式

全局有且仅有一个实例。

prototype原型模式

每次获取Bean的时候都会有一个新的实例。

request

request表示针对每次请求都会产生一个新的Bean对象,并且该Bean对象仅在当前Http请求内有效。

session

session作用域表示煤气请求都会产生一个新的Bean对象,并且该Bean仅在当前Http session内有效。

  AnnotationConfigApplicationContext
                context = new AnnotationConfigApplicationContext(MainConfig.class);
        UserService userService1 = context.getBean(UserService.class);
        UserService userService2 = context.getBean(UserService.class);
        System.out.println(userService1==userService2);结果为true

4.@Lazy

Lazy表示为懒加载,当真正需要引用获取的时候才会被加载

True 表示为懒加载 false表示为在IOC容器加载的时候被创建。

@Service
@Lazy(true)
public class UserService 
    public UserService() 
        System.out.println("UserService无参数构造被加载...");
    

 5.@Condition

Condition 是在spring4.0 增加的条件注解,通过这个可以功能可以实现选择性的注入Bean操作,接下来先学习下Condition是如何使用的,然后分析spring源码了解其中的实现原理。

实现案例:

在Spring容器加载中,如果当前环境是WIN7操作系统就装配win7实体类、其他系统就不装配。

//判断是否操作系统
public class MyCondition implements Condition 
    /@param context 获取当前的上下文路径
      @param metadata 获取当前的注解信息
      @return
     /
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) 
        //获取环境
        Environment environment = context.getEnvironment();
        // win7 linux win8 win10 苹果系统MAC
        String property = environment.getProperty("os.name");
        if(property.contains("Window"))
            return true;
        
        return false;
    

@Configuration
@Conditional(MyCondition.class)
public class MyConfig 

    @Bean
    public WindowEntity windowEntity()
        return new WindowEntity();
    

6.@import注解

@Import 是被用来整合所有在@Configuration注解中定义的bean配置,作用主要将外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等于与@Bean

public class MyEntity 

@Configuration
@Import(MyInportEntity.class)
public class MyImportConfig 

默认注册beanid为 全路径地址

@Import注解与@Bean注解区别:

bean注解注册的 bean的id是以方法名称 @Import以当前类完整路径地址注册 相比来说@Import注入类更加简单

7.@ImportSelector

ImportSelector接口是至spring中导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX(功能性注解)都有它的存在

public class MyInportSelectorEntity 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
//导入类
@Import(MyImportSelector.class)
public @interface EnableImport 

@Configuration
//使用自定义注解
@EnableImport
public class MyImportSelectorConfig 

 8.@ImportBeanDefinitionRegistrar

手动注册bean到容器

/
  手动注册
 /
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar 
    /
      AnnotationMetadata:当前类的注解信息
      BeanDefinitionRegistry:BeanDefinition注册类;
              把所有需要添加到容器中的bean;调用
              BeanDefinitionRegistry.registerBeanDefinition手工注册进来
     /
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry) 
        ////指定Bean定义信息;(Bean的类型,Bean。。。)
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(PayEntity.class);
        //注册一个Bean,指定bean名
        registry.registerBeanDefinition("payEntity",rootBeanDefinition);
    

9.使用FactoryBean注册对象

public class FactoryEntity 


//创建一个spring 定义的工厂bean
public class MyFactory implements FactoryBean<FactoryEntity> 

    //返回一个FactoryEntity 对象
    @Override
    public FactoryEntity getObject() throws Exception 
        return new FactoryEntity();
    

    @Override
    public Class<?> getObjectType() 
        return FactoryEntity.class;
    

    //是单例?
    //true:这个bean是单实例,在容器中保存一份
    //false:多实例,每次获取都会创建一个新的bean;
    @Override
    public boolean isSingleton() 
        return false;
    

@Configuration
public class MyFactoryCconfig 
    /
      使用Spring提供的 FactoryBean(工厂Bean);
                    1)、默认获取到的是工厂bean调用getObject创建的对象
                    2)、要获取工厂Bean本身,我们需要给id前面加一个&
                        &colorFactoryBean
      @return
     /
    @Bean
    public MyFactory myFactory()
        return new MyFactory();
    


public class MainTest 
    public static void main(String[] args) 
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(MyFactoryCconfig.class);
        Object myFactory = context.getBean("&myFactory");
        Object myFactory1 = context.getBean("myFactory");
        System.out.println(myFactory.getClass());
        System.out.println(myFactory1.getClass());
    

区别:BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。

(从IOC工厂中获取bean对象)

但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似

(往ioc容器中存储对象 注入对象)

@Service、@Repository 注入对象更好区分应用场景底层使用@Component 注意加上@Component扫包范围

@Qualifier与@Primary注解区别
1.@qualifier根据名称查找 @Primary设置默认的

10.AnnotationConfigApplicationContext注解启动原理

Spring有2个核心接口:BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口。
他们都可代表Spring容器,Spring容器生成Bean实例的工厂,并且管理容器中的Bean。
BeanFactory与ApplicationContext的作用和区别?
作用:
1.BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期
2.ApplicationContext 除了提供的上诉BeanFactory所提供的功能之外,还提供了更完整的框架功能:
a. 国际化支持
b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”
c. 事件传递:通过实现ApplicationContextAware接口
3. 常用的获取ApplicationContext的方法:
FileSystemXmlApplicationContext:从文件系统或者url指定的xml配置文件创建,参数为配置文件名或文件名数组
ClassPathXmlApplicationContext:从classpath的xml配置文件创建,可以从jar包中读取配置文件
WebApplicationContextUtils:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现
AnnotationConfigApplicationContext是基于注解来使用的,它不需要配置文件,采用java配置类和各种注解来配置,是比较简单的
方式,也是大势所趋

11.AnnotationConfig启动流程源码分析

    public AnnotationConfigApplicationContext() 
        //基于注解方式读取到ioc容器
        this.reader = new AnnotatedBeanDefinitionReader(this);
        //基于扫包方式读取到ioc容器
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
            @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) 
    //AnnotatedGenericBeanDefinition 注解方式启动的配置注入ioc bean信息
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    //判断是否有condition条件注入的bean
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) return;     //设置回调方式 abd.setInstanceSupplier(instanceSupplier);
    //判断config类上面是否加上@Scope作用域 ScopeMetadata scopeMetadata
= this.scopeMetadataResolver.resolveScopeMetadata(abd);
    //设置scope abd.setScope(scopeMetadata.getScopeName());
//判断是否有传递beanname如果没有传递name的话 生成的beanname 默认是类名的小写 String beanName
= (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) for (Class<? extends Annotation> qualifier : qualifiers) if (Primary.class == qualifier) abd.setPrimary(true); else if (Lazy.class == qualifier) abd.setLazyInit(true); else abd.addQualifier(new AutowireCandidateQualifier(qualifier)); for (BeanDefinitionCustomizer customizer : definitionCustomizers) customizer.customize(abd); BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

流程图

技术图片

 第二、spring的生命周期

2.1Bean实例生命周期的执行过程如下:

  • Spring对bean进行实例化,默认bean是单例;

  • Spring对bean进行依赖注入;

  • 如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法;

  • 如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法,将BeanFactory实例传进来;

  • 如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中;

  • 如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization方法将被调用;

  • 如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet接口方法,类似的如果bean使用了init-method属性声明了初始化方法,该方法也会被调用;

  • 如果bean实现了BeanPostProcessor接口,它的postProcessAfterInitialization接口方法将被调用;

  • 此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;

  • 若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。同样的,如果bean使用了destroy-method属性声明了销毁方法,则该方法被调用;

        SpringBean的生命周期Bean的创建(执行构造方法)→初始化(自定义init方法)→销毁
         可以自定义方法初始化与销毁的方法

2.2Bean实例创建时间

单实例:在容器启动的时候创建对象
多实例:在每次获取对象的时候创建对象,容器启动之后

@Scope("prototype")//多例情况下
@Component
public class MyEntity 

    public MyEntity()
        System.out.println(">>>>>>无参构造函数执行");
    

@Configuration
@ComponentScan("com.yehui.entity")
public class MyConfig 

public class Test001 

    public static void main(String[] args) 
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(MyConfig.class);
        // 单例和多例到底在什么时候初始化的呢 默认的情况下
        /
         1.单例默认情况下是在容器被加载的时候就会初始化
         2.多例子在每次获取bean的对象的时候就会去初始化
         
          如何判断对象是否初始化呢?
          通过构造函数
         /
        MyEntity bean = context.getBean(MyEntity.class);
    

2.3对象的初始化和销毁

1.对象的初始化:
对象创建完成,并赋值好,调用初始化方法。。。
2.对象的销毁
单实例:容器关闭的时候
多实例:容器不会管理这个bean;容器不会调用销毁方法;

初始化和销毁的方法
方法一.通过@Bean指定init-method和destroy-mothod;
方法二.通过让bean实现initializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
方法三、可以使用JSR250
@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
@PreDestroy:在容器销毁bean之前通知我们进行清理工作

方法一代码实现:

public class MyEntity 

    public MyEntity()
        System.out.println(">>>>>>无参构造函数执行");
    

    public void init()
        System.out.println("初始化方法");
    

    public void destroy()
        System.out.println("销毁方法");
    

@Configuration
@ComponentScan("com.yehui.entity")
public class MyConfig 

    /
      initMethod 指定初始化方法执行
      destroyMethod 指定销毁方法
      @return
     /
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public MyEntity myEntity()
        return new MyEntity();
    


public class Test001 

    public static void main(String[] args) 
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(MyConfig.class);
        /
          bean初始化 指的就是对象已经创建里面所有的set方法都已经执行完毕了;指定方法执行
          new User().setName
          调用close方法销毁单例对象 Map集合存储对象 clean清除
         /
        MyEntity bean = context.getBean(MyEntity.class);
        //销毁
        context.close();

    

方法二代码实现

@Component
public class MemberEntity implements InitializingBean,DisposableBean 

    public MemberEntity()
        System.out.println("构造函数创建");
    
    //1.对象创建 对象属性赋值 set方法全部走完
    @Override
    public void afterPropertiesSet() throws Exception 
        System.out.println("初始化");
    

    @Override
    public void destroy() throws Exception 
        System.out.println("销毁");
    

@Configuration
@ComponentScan("com.yehui.entity")
public class MyConfig 

public class Test001 

    public static void main(String[] args) 
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(MyConfig.class);
        /
          bean初始化 指的就是对象已经创建里面所有的set方法都已经执行完毕了;指定方法执行
          new User().setName
          调用close方法销毁单例对象 Map集合存储对象 clean清除
         /
        MemberEntity bean = context.getBean(MemberEntity.class);
        //销毁
        context.close();

    

方法三.代码实现

@Component
public class PosConstrutsEntity 

    public PosConstrutsEntity()
        System.out.println("这个是构造函数");
    
  //对象创建赋值之后调用
    @PostConstruct
    public  void init()
        System.out.println("初始化方法");
    
    //移除对象
    @PreDestroy
    public void destroy()
        System.out.println("销毁方法");
    

@Configuration
@ComponentScan("com.yehui.entity")
public class MyConfig 

public class Test001 

    public static void main(String[] args) 
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(MyConfig.class);

        PosConstrutsEntity bean = context.getBean(PosConstrutsEntity.class);
        //销毁
        context.close();

    

 2.4ApplicationContextAware接口

代码实现

@Component
public class MyApplicationContext implements ApplicationContextAware 

    ApplicationContext applicationContext;

    /
      spring底层中为什么能够实现ApplicationContextAware接口 就能够拿到ApplicationContext
          BeanPostProcessor(后置处理器作用就是可以对初始实现增强)
              过滤器中,是否可以使用注解方式获取bean对象 不可以(自己单独获取上下文 ApplicationContext)
      @param applicationContext
      @throws BeansException
     /
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
        this.applicationContext = applicationContext;
        Object memberEntity = applicationContext.getBean("memberEntity");
        System.out.println(memberEntity);
    

2.5BeanNameAware与BeanFactoryAware区别

技术图片

@Component
public class PayEntity implements BeanNameAware, BeanFactoryAware 
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException 
        System.out.println("设置beanName"+beanFactory);
    

    @Override
    public void setBeanName(String name) 
        System.out.println("name"+name);
    


@Configuration
@ComponentScan("com.yehui.entity")
public class MyConfig 


public class Test001 

    public static void main(String[] args) 
     //IOC容器初始化单例对象都是循环遍历调用getBean方法

AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(MyConfig.class); PayEntity bean = context.getBean(PayEntity.class); //销毁 context.close();

 2.6.BeanPostProcessor的作用

BeanPostProcessor.postProcessBeforeInitialization
初始化:
对象创建完成,并赋值好,调用初始化方法。。。
BeanPostProcessor.postProcessAfterInitialization

BeanPostProcessor【interface】:bean的后置处理器;

在bean初始化前后进行一些处理工作;
postProcessBeforeInitialization:在初始化之前工作
postProcessAfterInitialization:在初始化之后工作

 

遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization

BeanPostProcessor原理
populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
initializeBean

applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

Spring底层对 BeanPostProcessor 的使用;
bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) 
       //前置 wrappedBean
= applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); try
//执行自定义的初始化方法 invokeInitMethods(beanName, wrappedBean, mbd);
catch (Throwable ex) throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); if (mbd == null || !mbd.isSynthetic())
//后置 wrappedBean
= applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
@Configuration
@ComponentScan("com.yehui.entity")
public class MyConfig 

@Component
public class MyBeanPostProcessor implements BeanPostProcessor 

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException 
        System.out.println("方法之前执行:"+beanName);
        return bean;
    

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException 
        System.out.println("方法之后执行:"+beanName);
        return bean;
    

public class Test001 

    public static void main(String[] args) 
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(MyConfig.class);

        MyBeanPostProcessor bean = context.getBean(MyBeanPostProcessor.class);
        //销毁
        context.close();

    

 spring生命周期流程图

技术图片

 SpringBean的声明周期总结:

源码分析:

  1. 执行refresh() ; 刷新方法
  2. finishBeanFactoryInitialization()
  3. preInstantiateSingletons()
  4. getBean()→doGetBean()→createBean()→doCreateBean()→createBeanInstance(初始化对象)默认情况下使用Java的反射机制初始化对象, 也可以通过CGLIB实现初始化
  5. initializeBean()
  6. invokeAwareMethods() 判断是否有aware接口依赖信息
  7. applyBeanPostProcessorsBeforeInitialization()执行前置处理
  8. invokeInitMethods()执行init方法
  9. applyBeanPostProcessorsAfterInitialization 执行后置增强

 

核心的一个接口BeanPostProcessors 目的对我们bean对象自定义初始化方法实现曾强

如何知道Bean对象到底是如何创建的?

反射机制

第三.SpringAop的编程切面编程

3.1什么是AOP编程

Spring 的aop可以在方法之前和之后实现增强

Aop面向切面编程,在方法之前和之后实现处理 应用场景在于:日志打印、事务实现、安全等。

3.2AOP的底层实现原理

动态代理技术

基于Jdk实现InvocationHandler 底层使用反射技术(基于接口实现)

基于CGLIB实现 字节码技术(继承模式)

3.3基于注解方式启动Aop

引入maven依赖

 <dependencies>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
    </dependencies>

创建一个目标类

public class MathCalculator 
    public int div(int i,int j)
        System.out.println("MathCalculator...div...");
        return i/j;
    

创建一个切面类

/
  @Aspect: 告诉Spring当前类是一个切面类
 /
@Aspect
public class LogAspects 

    //抽取公共的切入点表达式
    //1、本类引用
    //2、其他的切面引用
    @Pointcut("execution(  com.yehui.aop..(..))")
    public void pointCut()
    

    //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint)
        //得到方法名
        String methodName = joinPoint.getSignature().getName();
        //得到参数
        Object[] params = joinPoint.getArgs();
        //得到类
        Class<?> clazz = joinPoint.getTarget().getClass();
        //得到方法的参数类型
        Class[] parameterTypes = ((MethodSignature) (joinPoint.getSignature())).getParameterTypes();
        System.out.println(""+joinPoint.getSignature()
                .getName()+"运行。。。@Before:参数列表是:" +
                ""+Arrays.asList(params)+""+"方法的参数类型"+parameterTypes);

    

    //后置通知
    @After("pointCut()")
    public void logEnd(JoinPoint joinPoint)
        System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
    

    /
      环绕通知
      @param joinPoint
      @return
      JoinPoint一定要出现在参数表的第一位
     /
    @AfterReturning(value = "pointCut()",returning = "result")
    public void logReturn(JoinPoint joinPoint,Object result)
        System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:"+result+"");
    
    @AfterThrowing(value="pointCut()",throwing="exception")
    public void logException(JoinPoint joinPoint,Exception exception)
        System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:"+exception+"");
    

 创建一个配置类

/
  AOP:【动态代理】
          指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;
 
  1、导入aop模块;Spring AOP:(spring-aspects)
  2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
  3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
          通知方法:
              前置通知(@Before):logStart:在目标方法(div)运行之前运行
              后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
              返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
              异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
              环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
  4、给切面类的目标方法标注何时何地运行(通知注解);
  5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
  6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
  [7]、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
          在Spring中很多的 @EnableXXX;
 
  三步:
      1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
      2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
   3)、开启基于注解的aop模式;@EnableAspectJAutoProxy
 /
@Configuration
@EnableAspectJAutoProxy
public class AopConfig 

    /
      配置一个切面类
      @return
     /
    @Bean
    public LogAspects logAspects()
        return new LogAspects();
    

    /
      目标方法类
      @return
     /
    @Bean
    public MathCalculator mathCalculator()
        return new MathCalculator();
    

启动测试

public class Test001 
    public static void main(String[] args) 
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AopConfig.class);
        MathCalculator mathCalculator = context.getBean(MathCalculator.class);
        mathCalculator.div(1,2);
    

 效果:

技术图片

3.4纯手写spring事物框架

实现思路:自定义注解加aop

引入maven依赖

  <groupId>com.yehui</groupId>
    <artifactId>spring-transactional</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>
    <dependencies>
        <!-- SpringBoot-整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- springboot-aop 技术 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- mysql 依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

 自定义注解

/
  自定义注解
 /
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExTransactional 
    String value() default "";

 事物工具类

@Component
public class TransactionalUtils 
    /
      获取当前事务管理器
     /
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    public TransactionStatus begin() 
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
        return transaction;
    


    public void rollback(TransactionStatus transaction) 
        dataSourceTransactionManager.rollback(transaction);
    

    public void commit(TransactionStatus transaction) 
        dataSourceTransactionManager.commit(transaction);
    

 aop类

/
  自定义注解+aop事物拦截
 /
@Aspect
@Component
public class TransactionalAop 

    @Autowired
    private TransactionalUtils transactionalUtils;
    @Around("@annotation(com.yehui.annontation.ExTransactional)")
    public Object aroundAnnotation(ProceedingJoinPoint joinPoint) throws Throwable 
        TransactionStatus transactionStatus = null;
        //获取目标类
        Class<?> clazz = joinPoint.getTarget().getClass();
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        //获取参数类型
        Class[] parameterTypes = ((MethodSignature) (joinPoint.getSignature())).getParameterTypes();
        //获取方法
        try 
            Method method = clazz.getMethod(methodName, parameterTypes);
            //获取是否有注解
            if(method.isAnnotationPresent(ExTransactional.class))
                //开启事物
                transactionStatus = transactionalUtils.begin();
                Object object = joinPoint.proceed();
                //提交事物
                transactionalUtils.commit(transactionStatus);
                return object;
            
         catch (NoSuchMethodException e) 
            e.printStackTrace();
         catch (Throwable throwable) 
            // 目标方法抛出异常的情况下 回滚当前事务
            transactionalUtils.rollback(transactionStatus);
            return 0;
        
        return joinPoint.proceed();

    

 创建一个mapper接口

@Mapper
public interface AccountMapper 

    @Update("UPDATE account SET money = money-1000 WHERE id = 4")
    public void update();

 service类

@Service
public class AccountService 

    @Autowired
    private AccountMapper accountMapper;

    @ExTransactional
    public void update()
        accountMapper.update();
        //int i=1/0;
    

 controller类

@RestController
public class AccountController 
    @Autowired
    private AccountService accountService;

    @RequestMapping("/update")
    public void update()
        accountService.update();
    

yml配置文件

spring:
###数据库相关连接      
  datasource:
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/study?useUnicode=true&characterEncoding=UTF-8 

 启动类

@SpringBootApplication
public class AopStartApp 
    public static void main(String[] args) 
        SpringApplication.run(AopStartApp.class);
    

 3.5springAop原理分析

如何分析原理:【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】

3.5.1@EnableAspectJAutoProxy是什么?

@Import(AspectJAutoProxyRegistrar.class):给容器中导入AspectJAutoProxyRegistrar

利用AspectJAutoProxyRegistrar自定义给容器中注册bean;BeanDefinetion

注册bean信息:    

       Beanid:org.springframework.aop.config.internalAutoProxyCreator

       class:AnnotationAwareAspectJAutoProxyCreator

给容器中注册一个AnnotationAwareAspectJAutoProxyCreator;需要了解SpringAOP底层是如何实现的 离不开

AnnotationAwareAspectJAutoProxyCreator

  得出结论:AnnotationAwareAspectJAutoProxyCreator祖宗是BeanPostProcessors子类。

3.5.2   AnnotationAwareAspectJAutoProxyCreator:

   1.继承关系

    AnnotationAwareAspectJAutoProxyCreator
      →AspectJAwareAdvisorAutoProxyCreator
         →AbstractAdvisorAutoProxyCreator
           →AbstractAutoProxyCreator
             →implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
                →关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory

AbstractAutoProxyCreator.setBeanFactory()

AbstractAutoProxyCreator.postProcessAfterInstantiation()后置处理器

AbstractAdvisorAutoProxyCreator.setBeanFactory()-》initBeanFactory()

 AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()

   2.执行流程

  1)传入配置类,创建ioc容器;

        2)注册配置类,调用refresh()刷新容器;

        3)registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;

                 1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor

                  2)、给容器中加别的BeanPostProcessor

                  3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;

                  4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;

                  5)、注册没实现优先级接口的BeanPostProcessor;

                   6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;

                           创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】

                             1)、创建Bean的实例

                             2)、populateBean;给bean的各种属性赋值

                             3)、initializeBean:初始化bean;

                                     1)、invokeAwareMethods():处理Aware接口的方法回调

                                     2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()

                                     3)、invokeInitMethods();执行自定义的初始化方法

                                          4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();

                             4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder

                 7)、把BeanPostProcessor注册到BeanFactory中;

                             beanFactory.addBeanPostProcessor(postProcessor);

=======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程========

                 AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor

 

       4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;创建剩下的单实例bean

               1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);

                 getBean->doGetBean()->getSingleton()->

              2)、创建bean

                     【AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation

                      1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;

                            只要创建好的Bean都会被缓存起来

                      2)、createBean();创建bean;

                            AnnotationAwareAspectJAutoProxyCreator 会在任何bean创建之前先尝试返回bean的实例

                          【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】

                          【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的】

                          1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation

                                    希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续

                                      1)、后置处理器先尝试返回对象;

                                         bean = applyBeanPostProcessorsBeforeInstantiation():

                                                  拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;

                                                    就执行postProcessBeforeInstantiation

                                                     if (bean != null)

                                                       bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

                                                     

             doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例;和3.6流程一样

 

 AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】 的作用:

1)、每一个bean创建之前,调用postProcessBeforeInstantiation();

         1)、判断当前bean是否在advisedBeans中(保存了所有需要增强bean)

        2)、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,或者是否是切面(@Aspect)

         3)、是否需要跳过   

                    1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】

                        每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;

                         判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true 

                     2)、永远返回false

2)、创建对象

   postProcessAfterInitialization;

    return wrapIfNecessary(bean, beanName, cacheKey);//包装如果需要的情况下

  1)、获取当前bean的所有增强器(通知方法)  Object[]  specificInterceptors

              1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)

             2、获取到能在bean使用的增强器。

             3、给增强器排序

       2)、保存当前bean在advisedBeans中;

         3)、如果当前bean需要增强,创建当前bean的代理对象;
                 1)、获取所有增强器(通知方法)
                 2)、保存到proxyFactory
                 3)、创建代理对象:Spring自动决定
                      JdkDynamicAopProxy(config);jdk动态代理;
                       ObjenesisCglibAopProxy(config);cglib的动态代理;
       4)、给容器中返回当前组件使用cglib增强了的代理对象;
       5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;

3)目标方法的执行

  容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);

     1)、CglibAopProxy.intercept();拦截目标方法的执行

     2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;

            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

             1)、List<Object> interceptorList保存所有拦截器 5

                      一个默认的ExposeInvocationInterceptor 和 4个增强器;

             2)、遍历所有的增强器,将其转为Interceptor;

                 registry.getInterceptors(advisor);

              3)、将增强器转为List<MethodInterceptor>;

                  如果是MethodInterceptor,直接加入到集合中
                  如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
                 转换完成返回MethodInterceptor数组;

    3)、如果没有拦截器链,直接执行目标方法;

                    拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)

        4)、如果有拦截器链,把需要执行的目标对象,目标方法,

                     拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用 Object retVal =  mi.proceed();

         5)、拦截器链的触发过程;

                          1)、如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
                          2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
                            拦截器链的机制,保证通知方法与目标方法的执行顺序;

技术图片

总结:
1)、 @EnableAspectJAutoProxy 开启AOP功能
2)、 @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
4)、容器的创建流程:
1)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
2)、finishBeanFactoryInitialization()初始化剩下的单实例bean
1)、创建业务逻辑组件和切面组件
2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
3)、组件创建完之后,判断组件是否需要增强
是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
5)、执行目标方法:
1)、代理对象执行目标方法
2)、CglibAopProxy.intercept();
1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
3)、效果:
正常执行:前置通知-》目标方法-》后置通知-》返回通知
出现异常:前置通知-》目标方法-》后置通知-》异常通知

3.6spring aop调用链实现

3.6.1Aop底层原理分析

1.首先启动Spring Aop时,会使用@EnableAspectJAutoProxy注解

2.将@Import(AspectJAutoProxyRegistrar.class)注入到spring aop容器中

3.AspectJAutoProxyRegistrar会注册对象

BeanId:internalAutoProxyCreator

BeanClass:AnnotationAwareAspectJAutoProxyCreator

4.AnnotationAwareAspectJAutoProxyCreator最为核心,使用后置通知在bean的对象初始化的时候,实现对代理对象的增强。

     AnnotationAwareAspectJAutoProxyCreator祖宗:

      AbstractAutoProxyCreator 祖宗有是BeanPostProcessor

5.被代理对象在初始化的时候,AbstractAutoProxyCreator 经过这样的一个类拦截。

  1. 判断该被代理对象是否有被有实现过接口,如果有实现过接口就使用jdk动态代理,如果没有实现接口则使用cglib动态代理。

3.6.2模拟SpringAop五个通知调用链关系

创建一个UserService接口

public class UserService 

    public void login(String name,String  age)
        System.out.println("姓名:"+name);
        System.out.println("年龄:"+age);
    

 创建方法拦截接口

/
  定义一个通知接口
 /
public interface MethodInterceptor 
    /
      定义一个共同骨架
     /
    public void invoke(MethodInvocation methodInvocation);

创建一个前置通知

/
  前置通知
 /
public class BeforMethodInterceptor implements MethodInterceptor 
    @Override
    public void invoke(MethodInvocation methodInvocation) 
        System.out.println("前置通知=====");
        //执行目标方法
        methodInvocation.procee();
    

创建一个后置通知

public class AfterMethodInterceptor implements MethodInterceptor 
    @Override
    public void invoke(MethodInvocation methodInvocation) 
        //执行目标方法
        methodInvocation.procee();
        System.out.println("后置通知");
    

创建一个环绕通知

public class AroundMethodInterceptor implements MethodInterceptor 
    public Object invoke(MethodInvocation methodInvocation) throws InvocationTargetException, IllegalAccessException 
        System.out.println("环绕通知之前执行....");
        Object process = methodInvocation.process();
        System.out.println("环绕通知之后执行....");
        return process;
    

 方法执行接口

/
  调用方法
 /
public interface MethodInvocation 

    /
      调用链
     /
    public void procee();

 方法执行接口实现类

public class DefaultMethodInvacation implements MethodInvocation 
    /
      存放调用链集合
     /
    List<MethodInterceptor> methodInterceptors = new ArrayList<>();

    private Object target;//目标对象
    private Method method;//方法
    private Object[] args;//参数名称
    private int index = 0;
    public DefaultMethodInvacation(List<MethodInterceptor> methodInterceptors)
        this.methodInterceptors = methodInterceptors;
    

    public DefaultMethodInvacation(List<MethodInterceptor> methodInterceptors,
                                   Object target,Method method,Object[] args)
        this.methodInterceptors = methodInterceptors;
        this.target = target;
        this.method = method;
        this.args =args;
    
    @Override
    public void procee() 
        if (methodInterceptors.size()==index)
            try 
                 method.invoke(target,args);//执行目标方法
                return;
             catch (IllegalAccessException e) 
                e.printStackTrace();
             catch (InvocationTargetException e) 
                e.printStackTrace();
            
        
        MethodInterceptor methodInterceptor = methodInterceptors.get(index++);
        methodInterceptor.invoke(this);
    

测试

public class Test001 
    public static void main(String[] args) throws NoSuchMethodException 
        List<MethodInterceptor> methodInterceptors = new ArrayList<>();
        methodInterceptors.add(new BeforMethodInterceptor());
        methodInterceptors.add(new AfterMethodInterceptor());
        UserService userService = new UserService();
        Method loginMethod = userService.getClass().getMethod("login", String.class, String.class);
        DefaultMethodInvacation defaultMethodInvacation =
                new DefaultMethodInvacation(methodInterceptors,new UserService(),
                        loginMethod, new Object[]"yehui","12323");
        defaultMethodInvacation.procee();//spring Aop底层 所有的通知最终使用递归算法调用+责任链设计模式
    

3.7 声明式事务

事物本身就是基于aop实现的

SpringAop通知链采用递归+责任链设计模式实现

技术图片

技术图片

 环境搭建:

1、导入相关依赖
数据源、数据库驱动、Spring-jdbc模块

2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据

@Configuration
@EnableTransactionManagement
public class TxConfig 

    /
      配置数据源
      @return
     /
    @Bean
    public DataSource dataSource()
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("123456");
        try 
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
         catch (PropertyVetoException e) 
            e.printStackTrace();
        
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        return dataSource;
    

    @Bean
    public JdbcTemplate jdbcTemplate()
        //Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
        return new JdbcTemplate(dataSource());
    

    //注册事务管理器在容器中
    @Bean
    public PlatformTransactionManager transactionManager() throws Exception
        return new DataSourceTransactionManager(dataSource());
    

@Service
public class UserService 
    
    @Autowired
    private UserDao userDao;
    
    @Transactional
    public void insertUser()
        userDao.insert();
        //otherDao.other();xxx
        System.out.println("插入完成...");
        int i = 10/0;
    

@Repository
public class UserDao 
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public void insert()
        String sql = "INSERT INTO `tbl_user`(username,age) VALUES(?,?)";
        String username = UUID.randomUUID().toString().substring(0, 5);
        jdbcTemplate.update(sql, username,19);
        
    

3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
@EnableXXX
5、配置事务管理器来控制事务;
@Bean
public PlatformTransactionManager transactionManager()

6、原理:

    1)@EnableTransactionManagement

    1、利用TransactionManagementConfigurationSelector给容器导入组件

                       导入2个组件

                      AutoProxyRegistrar

                      ProxyTransactionManagementConfiguration

               2、AutoProxyRegistrar

                           给容器注册了一个InfrastructureAdvisorAutoProxyCreator组件

                             InfrastructureAdvisorAutoProxyCreator:利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;

                 3、ProxyTransactionManagementConfiguration 做了什么?

                       1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解

                     2)、事务拦截器:                           

                                       TransactionInterceptor;保存了事务属性信息,事务管理器;封装了事务的开启、提交、回滚。

                                        他是一个 MethodInterceptor;
                                        在目标方法执行的时候;
                                        执行拦截器链;
                                       事务拦截器:
                                       1)、先获取事务相关的属性
                                        2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger
                                           最终会从容器中按照类型获取一个PlatformTransactionManager;
                                        3)、执行目标方法
                                        如果异常,获取到事务管理器,利用事务管理回滚操作;
                                         如果正常,利用事务管理器,提交事务           

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) 
        // 开启事务
        TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
        Object retVal = null;
        try 
            // 执行目标方法
            retVal = invocation.proceedWithInvocation();
        
        catch (Throwable ex) 
            // 回滚当前事务
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        
        finally 
            cleanupTransactionInfo(txInfo);
        
//提交当前事务
        commitTransactionAfterReturning(txInfo);
        return retVal;
    

 Spring的事务为什么会失效呢?

技术图片

如果service 没有将异常抛出的时候,事务可能会失效

3.9扩展原理

 

/**
 * 扩展原理:
 *     BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的
 *     BeanFactoryPostProcessor:beanFactory的后置处理器
 *  1、BeanFactoryPostProcessor:beanFactory的后置处理器;
 *    所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建
*   BeanFactoryPostProcessor原理:
 *    1)ioc容器创建对象
 *    2)invokeBeanFactoryPostProcessors(beanFactory);
 *      如何找到所有的BeanFactoryPostProcessor并执行他们的方法;
 *      1)、直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法
 *        2)、在初始化创建其他组件前面执行
 *  2、BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
 *  postProcessBeanDefinitionRegistry();
 *  在所有bean定义信息将要被加载,bean实例还未创建的;
 *  优先于BeanFactoryPostProcessor执行;
 *   利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件;
 *   原理:
 *      1)ioc容器创建
 *      2)refresh()-》invokeBeanFactoryPostProcessors(beanFactory);
 *      3)从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件。
 *         1、依次触发所有的postProcessBeanDefinitionRegistry()方法
 *         2、再来触发postProcessBeanFactory()方法BeanFactoryPostProcessor;
*       4)、再来从容器中找到BeanFactoryPostProcessor组件;然后依次触发postProcessBeanFactory()方法
*   3、ApplicationListener:监听容器中发布的事件。事件驱动模型开发;
 *       public interface ApplicationListener<E extends ApplicationEvent>
 *           监听 ApplicationEvent 及其下面的子事件;
 *       步骤:
 *           1)、写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)
 *           2)、把监听器加入到容器;
 *           3)、只要容器中有相关事件的发布,我们就能监听到这个事件;
 *                      ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件;
 *                      ContextClosedEvent:关闭容器会发布这个事件;
*            4)、发布一个事件:
 *            applicationContext.publishEvent();
 *    原理:
 *        1)、ContextRefreshedEvent事件:
 *              1)、容器创建对象:refresh();
 *              2)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
 *        2)、自己发布事件;
 *        3)、容器关闭会发布ContextClosedEvent;
 *         【事件发布流程】:
 *                3)、publishEvent(new ContextRefreshedEvent(this));
 *                    1)、获取事件的多播器(派发器):getApplicationEventMulticaster()
 *                    2)、multicastEvent派发事件:
 *                    3)、获取到所有的ApplicationListener;
 *                    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) 
 *                    1)、如果有Executor,可以支持使用Executor进行异步派发;
 *                    Executor executor = getTaskExecutor();
 *                    2)、否则,同步的方式直接执行listener方法;invokeListener(listener, event);
 *                    拿到listener回调onApplicationEvent方法;
*           【事件多播器(派发器)】
 *           1)、容器创建对象:refresh();
 *           2)、initApplicationEventMulticaster();初始化ApplicationEventMulticaster;
 *               1)、先去容器中找有没有id=“applicationEventMulticaster”的组件;
 *               2)、如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
 *               并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster;
*           【容器中有哪些监听器】
 *           1)、容器创建对象:refresh();
 *           2)、registerListeners();
 *           从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;
 *           String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
 *            //将listener注册到ApplicationEventMulticaster中
 *            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
 *
 *     SmartInitializingSingleton 原理:->afterSingletonsInstantiated();
 *             1)、ioc容器创建对象并refresh();
 *             2)、finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean;
 *                 1)、先创建所有的单实例bean;getBean();
 *                 2)、获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的;
 *                     如果是就调用afterSingletonsInstantiated();
 *
 */
@ComponentScan("com.yehui.ex")
@Configuration
public class ExConfig 

    @Bean
    public Blue blue()
        return  new Blue();
    

 

 

 

 

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor 
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException 
        System.out.println("postProcessBeanDefinitionRegistry:\\t"+registry.getBeanDefinitionCount());
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Blue.class);
        registry.registerBeanDefinition("hello",rootBeanDefinition);
    

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException 
        System.out.println("postProcessBeanFactory:\\t\\t--"+beanFactory.getBeanDefinitionCount());
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        System.out.println("postProcessBeanFactory:\\t"+Arrays.asList(beanDefinitionNames));
    

 

 

 

 

public class Blue 
    
    public Blue()
        System.out.println("blue...constructor");
    
    
    public void init()
        System.out.println("blue...init...");
    
    
    public void detory()
        System.out.println("blue...detory...");
    

 

 

 

3.10spring的创建

 

Spring容器的refresh()【创建刷新】;
1、prepareRefresh()刷新前的预处理;
     1)、initPropertySources()初始化一些属性设置;子类自定义个性化的属性设置方法;
    2)、getEnvironment().validateRequiredProperties();检验属性的合法等
    3)、earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>();保存容器中的一些早期的事件;
2、obtainFreshBeanFactory();获取BeanFactory;
    1)、refreshBeanFactory();刷新【创建】BeanFactory;
            创建了一个this.beanFactory = new DefaultListableBeanFactory();
            设置id;
     2)、getBeanFactory();返回刚才GenericApplicationContext创建的BeanFactory对象;
      3)、将创建的BeanFactory【DefaultListableBeanFactory】返回;
3、prepareBeanFactory(beanFactory);BeanFactory的预准备工作(BeanFactory进行一些设置);
       1)、设置BeanFactory的类加载器、支持表达式解析器...
       2)、添加部分BeanPostProcessor【ApplicationContextAwareProcessor】
        3)、设置忽略的自动装配的接口EnvironmentAware、EmbeddedValueResolverAware、xxx;
        4)、注册可以解析的自动装配;我们能直接在任何组件中自动注入:
          BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
         5)、添加BeanPostProcessor【ApplicationListenerDetector】
       6)、添加编译时的AspectJ;
        7)、给BeanFactory中注册一些能用的组件;
          environment【ConfigurableEnvironment】、
            systemProperties【Map<String, Object>】、
           systemEnvironment【Map<String, Object>】
4、postProcessBeanFactory(beanFactory);BeanFactory准备工作完成后进行的后置处理工作;
1)、子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置
======================以上是BeanFactory的创建及预准备工作==================================
5、invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor的方法;
BeanFactoryPostProcessor:BeanFactory的后置处理器。在BeanFactory标准初始化之后执行的;
两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
             1)、执行BeanFactoryPostProcessor的方法;
                先执行BeanDefinitionRegistryPostProcessor
            2)、获取所有的BeanDefinitionRegistryPostProcessor;
            2)、看先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、
               postProcessor.postProcessBeanDefinitionRegistry(registry)
              3)、在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor;
            postProcessor.postProcessBeanDefinitionRegistry(registry)
             4)、最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors;
           postProcessor.postProcessBeanDefinitionRegistry(registry)
            再执行BeanFactoryPostProcessor的方法
           1)、获取所有的BeanFactoryPostProcessor
           2)、看先执行实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor、
           postProcessor.postProcessBeanFactory()
           3)、在执行实现了Ordered顺序接口的BeanFactoryPostProcessor;
           postProcessor.postProcessBeanFactory()
          4)、最后执行没有实现任何优先级或者是顺序接口的BeanFactoryPostProcessor;
            postProcessor.postProcessBeanFactory()
6、registerBeanPostProcessors(beanFactory);注册BeanPostProcessor(Bean的后置处理器)【 intercept bean creation】
不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的
BeanPostProcessor、
DestructionAwareBeanPostProcessor、
InstantiationAwareBeanPostProcessor、
SmartInstantiationAwareBeanPostProcessor、
MergedBeanDefinitionPostProcessor【internalPostProcessors】、

    1)、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
    2)、先注册PriorityOrdered优先级接口的BeanPostProcessor;
        把每一个BeanPostProcessor;添加到BeanFactory中
        beanFactory.addBeanPostProcessor(postProcessor);
   3)、再注册Ordered接口的
  4)、最后注册没有实现任何优先级接口的
   5)、最终注册MergedBeanDefinitionPostProcessor;
   6)、注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是
          applicationContext.addApplicationListener((ApplicationListener<?>) bean);
7、initMessageSource();初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
   1)、获取BeanFactory
   2)、看容器中是否有id为messageSource的,类型是MessageSource的组件
   如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;
  MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
   3)、把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource;
    beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
   MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale);
8、initApplicationEventMulticaster();初始化事件派发器;
     1)、获取BeanFactory
    2)、从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
    3)、如果上一步没有配置;创建一个SimpleApplicationEventMulticaster
    4)、将创建的ApplicationEventMulticaster添加到BeanFactory中,以后其他组件直接自动注入
9、onRefresh();留给子容器(子类)
         1、子类重写这个方法,在容器刷新的时候可以自定义逻辑;
10、registerListeners();给容器中将所有项目里面的ApplicationListener注册进来;
            1、从容器中拿到所有的ApplicationListener
            2、将每个监听器添加到事件派发器中;
               getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
            3、派发之前步骤产生的事件;
11、finishBeanFactoryInitialization(beanFactory);初始化所有剩下的单实例bean;
    1、beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean
        1)、获取容器中的所有Bean,依次进行初始化和创建对象
         2)、获取Bean的定义信息;RootBeanDefinition
           3)、Bean不是抽象的,是单实例的,是懒加载;
      1)、判断是否是FactoryBean;是否是实现FactoryBean接口的Bean;
       2)、不是工厂Bean。利用getBean(beanName);创建对象
0、getBean(beanName); ioc.getBean();
1、doGetBean(name, null, null, false);
2、先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来)
从private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);获取的
3、缓存中获取不到,开始Bean的创建对象流程;
4、标记当前bean已经被创建
5、获取Bean的定义信息;
6、【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】
7、启动单实例Bean的创建流程;
    1)、createBean(beanName, mbd, args);
     2)、Object bean = resolveBeforeInstantiation(beanName, mbdToUse);让BeanPostProcessor先拦截返回代理对象;
      【InstantiationAwareBeanPostProcessor】:提前执行;
     先触发:postProcessBeforeInstantiation();
   如果有返回值:触发postProcessAfterInitialization();
     3)、如果前面的InstantiationAwareBeanPostProcessor没有返回代理对象;调用4)
    4)、Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean
   1)、【创建Bean实例】;createBeanInstance(beanName, mbd, args);
利用工厂方法或者对象的构造器创建出Bean实例;
2)、applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName);
3)、【Bean属性赋值】populateBean(beanName, mbd, instanceWrapper);
赋值之前:
1)、拿到InstantiationAwareBeanPostProcessor后置处理器;
postProcessAfterInstantiation();
2)、拿到InstantiationAwareBeanPostProcessor后置处理器;
postProcessPropertyValues();
=====赋值之前:===
3)、应用Bean属性的值;为属性利用setter方法等进行赋值;
applyPropertyValues(beanName, mbd, bw, pvs);
4)、【Bean初始化】initializeBean(beanName, exposedObject, mbd);
1)、【执行Aware接口方法】invokeAwareMethods(beanName, bean);执行xxxAware接口的方法
BeanNameAware\\BeanClassLoaderAware\\BeanFactoryAware
2)、【执行后置处理器初始化之前】applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
BeanPostProcessor.postProcessBeforeInitialization();
3)、【执行初始化方法】invokeInitMethods(beanName, wrappedBean, mbd);
1)、是否是InitializingBean接口的实现;执行接口规定的初始化;
2)、是否自定义初始化方法;
4)、【执行后置处理器初始化之后】applyBeanPostProcessorsAfterInitialization
BeanPostProcessor.postProcessAfterInitialization();
5)、注册Bean的销毁方法;
5)、将创建的Bean添加到缓存中singletonObjects;
ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息。。。。;
所有Bean都利用getBean创建完成以后;
检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated();
12、finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成;
1)、initLifecycleProcessor();初始化和生命周期有关的后置处理器;LifecycleProcessor
默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor();
加入到容器;

写一个LifecycleProcessor的实现类,可以在BeanFactory
void onRefresh();
void onClose();
2)、 getLifecycleProcessor().onRefresh();
拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh();
3)、publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件;
4)、liveBeansView.registerApplicationContext(this);

3.11Spring的源码总结 

1)、Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息;
1)、xml注册bean;<bean>
2)、注解注册Bean;@Service、@Component、@Bean、xxx
2)、Spring容器会合适的时机创建这些Bean
1)、用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中;
2)、统一创建剩下所有的bean的时候;finishBeanFactoryInitialization();
3)、后置处理器;BeanPostProcessor
1)、每一个bean创建完成,都会使用各种后置处理器进行处理;来增强bean的功能;
AutowiredAnnotationBeanPostProcessor:处理自动注入
AnnotationAwareAspectJAutoProxyCreator:来做AOP功能;
xxx....
增强的功能注解:
AsyncAnnotationBeanPostProcessor
....
4)、事件驱动模型;
ApplicationListener;事件监听;
ApplicationEventMulticaster;事件派发:

















 

 



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                          

 

以上是关于spring注解版的主要内容,如果未能解决你的问题,请参考以下文章

Spring 注解版 学习笔记AnnotationConfigApplicationContext

Spring的第四天AOP之注解版

spring注解版

玩转SSH:Struts + Spring + MyBatis(注解版)

Spring 注解版 学习笔记组件赋值

Spring 注解版 学习笔记组件添加