Java注解详解

Java内置注解

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

作用在其他注解的注解(或者说 元注解)是:

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

从 Java 7 开始,额外添加了 3 个注解:

  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次

Annotation 组成部分

java Annotation 的组成中,有 3 个非常重要的主干类。它们分别是:

Annotation.java

package java.lang.annotation;
public interface Annotation {

  boolean equals(Object obj);

  int hashCode();

  String toString();

  Class<? extends Annotation> annotationType();
}

ElementType.java

package java.lang.annotation;

public enum ElementType {
    /* 类、接口(包括注释类型)、枚举或记录声明  */
    TYPE,

    /* 字段声明(包括枚举常量)*/
    FIELD,

    /* 方法声明 */
    METHOD,

    /* 参数声明 */
    PARAMETER,

    /* 构造方法声明 */
    CONSTRUCTOR,

    /* 局部变量声明 */
    LOCAL_VARIABLE,

    /* 注解类型的声明 */
    ANNOTATION_TYPE,

    /* 包声明 */
    PACKAGE,

    /* 类型参数声明 */
    TYPE_PARAMETER,

    /* 类型使用 */
    TYPE_USE,

    /* 模块声明 */
    MODULE,

    /**
     * {@preview Associated with records, a preview feature of the Java language.
     *
     *           This constant is associated with <i>records</i>, a preview
     *           feature of the Java language. Programs can only use this
     *           constant when preview features are enabled. Preview features
     *           may be removed in a future release, or upgraded to permanent
     *           features of the Java language.}
     *
     * Record component*/
    @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
                                 essentialAPI=true)
    RECORD_COMPONENT;
}

RetentionPolicy.java

public enum RetentionPolicy {
    /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了  */
    SOURCE,

    /* 编译器将Annotation存储于类对应的.class文件中。默认行为  */
    CLASS,

    /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
    RUNTIME
}

spring注解驱动开发

1. 组件注册

  1. 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component/)(仅限自己写的

  2. @Bean 导入第三方的组件

  3. @Import (快速给容器一个组件)

    1. @Import({导入的组件类.class…}),容器会自动注册这个组件,id默认是全类名

    2. @ImportSelector:返回导入到容器中的组件的全类名数组(不能返回null)

      @Import(@MyImportSelector.class)

    3. @ImportBeanDefinitionRegistrar 手动注册组件

  4. spring的FactoryBean创建Bean(工厂Bean)

    1. 默认获取的bean为工厂创建的对象,返回工厂对象用&FactoryBean

1.1 @Configuration&@Bean注册组件

  • 编写注解config配置类和bean类,在config配置类中通过@Bean注册bean
  • 获取注解上下文(AnnotationContext(config配置类.class))
  • 通过上下文获取组件(context.getBean(组件类.class组件名))
@Configuration
public class AnnotionConfig {

    @Bean(value="组件名")
    public BeanClass bean(){
        return new BeanClass();
    }
}
@SpringBootTest
class SpringAnnoationApplicationTests {

    @Test
    void contextLoads() {
        ApplicationContext context = new AnnotationConfigApplicationContext(AnnotionConfig.class);
        BeanClass bean = context.getBean(BeanClass.class);
        System.out.println(bean);
    }

}

1.2 @ConponentScan注册组件

  • springmvc通过xml文件<context:component-scan base-package="包名"/>
  • springboot按包名可自动扫描,可@ComponentScan(“包名”)扫描,如mybatis的@mapper注解不属于spring注解,在使用过程中会爆红,可通过@ComponentScan扫描注入@mapper注解
1.2.1 TypeFilter过滤

TypeFilte用于扫描包中组件的过滤,可以扫描指定组件或排除指定组件

  • @excludeFilters = Filter[] : 扫描时按对应规则删除组件
  • @includeFilters = Filter[] : 扫描只包含对应组件
FilterType过滤规则
ANNOTATION按照注解过滤
ASSIGNABLE_TYPE按照给定类型过滤
ASPECTJ使用ASPECTJ表达式过滤
REGEX使用正则指定
CUSTOM自定义规则
@ComponentScan(value = "com.hz.config",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Configuration.class})
},useDefaultFilters = false)
public class SpringAnnoationApplication {

}

使用自定义过滤器过滤

public class MyFilter implements TypeFilter {

    /*
        metadataReader : 读取到当前正在扫描的类的信息
        metadataReaderFactory : 可以获取到其他任何类的信息
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        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;
    }
}
@ComponentScan(value = "com.hz.config",includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyFilter.class})
},useDefaultFilters = false)
public class SpringAnnoationApplication {
}

1.3 @Scope

作用域模式
prototype(default)单例模式
singleton多例子模式
request每次请求加载一次
session同一个session创建一个实例
public class AnnotionConfig {

    //默认单实例
    /*
     * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE prototype 单例模式
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON singleton 多例模式
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST 同一个请求加载一次
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION 同一次session加载一次
    */
    @Scope("singleton")
    @Bean()
    public BeanClass bean(){
        return new BeanClass();
    }
}

1.4 @Lazy 懒加载机制

  • lazy懒加载机制(可与@Scope搭配作用,在使用的时候再创造实例)

1.5 @Conditional

@Target({ElementType.TYPE, ElementType.METHOD})作用域

@Conditional : 按照一定条件进行判断,满足条件再注册bean

例:

要求:在windows系统下创造windows_bean,Linux系统下注册linux_bean

步骤:

  • 创建windows_bean和linux_bean

  • 创建自定义Conditon类,继承org.springframework.context.annotation.Condition

    public class MyCondition implements Condition {
        /*
            ConditionContext : 判断当前环境能使用的上下文
            AnnotatedTypeMetadata : 注释信息
         */
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();//获取IOC的beanfactory
            ClassLoader classLoader = context.getClassLoader();//获取类加载器
            Environment environment = context.getEnvironment();//获取当前环境
            BeanDefinitionRegistry registry = context.getRegistry();//获取bean定义的注册类
            String property = environment.getProperty("os.name");
            if(property.contains("Windows")){
                return true;
            }
            return false;
        }
    }
    
  • 在bean的注册位置添加@Conditional({MyCondition.class})

1.6 @Import & @ImportSelector & ImportBeanDefinitionRegistrar

使用方法:@Import({组件1.class,组件2.class...})

//自定义逻辑返回导入组件
public class MyImportSelector implements ImportSelector {

    /*
        返回值为导入容器中组件的全类名
        AnnotationMetadata : 当前标注@Import注解的类的所有注解信息
        不能返回null
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.hz.pojo.Beanclass"};
    }

}
public class MyImportBeanDefinitionRegistor implements ImportBeanDefinitionRegistrar {
    /*
        AnnotationMetadata : 当前类的注解信息
        BeanDefinitionRegistry : BeanDefinition注册类
            把所有需要添加到容器中的bean,调用registry.registerBeanDefinition()手动注册进来
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //条件判断....
        
        
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(BeanClass.class);
        registry.registerBeanDefinition("bean名",rootBeanDefinition);//指定Bean名
        
    }

}
public class MyFactoryBean implements FactoryBean<BeanClass> {

    //返回一个BeanClass并注入容器
    @Override
    public BeanClass getObject() throws Exception {
        return new BeanClass();
    }

    //返回类型
    @Override
    public Class<?> getObjectType() {
        return BeanClass.class;
    }
}

2. 生命周期

applicationcontext.close();关闭容器

bean单实例,在容器关闭时销毁

​ 多实例,容器部管理多实例的bean,容器不会调用销毁方法

2.1 Bean指定初始化和销毁

  • springmvcBean的初始化与销毁,通过xml中<bean id="" .. init-method="初始化方法" destory-method="销毁方法"/>

  • @Bean注解指定初始化和销毁(初始化:对象创建完成并赋值,若Bean为多实例,则在容器启动时只构造bean类而不进行初始化赋值,并且容器关闭时不会调用销毁方法)

    @Bean(initMethod = "init",destroyMethod = "destory")
        public BeanClass bean(){
            return new BeanClass();
        }
    
    
    public class BeanClass {
        public BeanClass(){
            System.out.println("Beanclass ... constructor..");
        }
    
        public void init(){
            System.out.println("Beanclass ... init ...");
        }
    
        public void destory(){
            System.out.println("Beanclass .. destory");
        }
    }
    
  • 通过让InitializingBean DisposableBean 实现

    public class BeanClassInitAndDestory implements InitializingBean, DisposableBean {
        public BeanClassInitAndDestory(){
            System.out.println("类构造");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("销毁方法");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("初始化方法");
        }
    }
    
    
  • 使用SR250中的注解

    • @PostConstruct : 在Bean创建并属性赋值完成执行初始化Bean方法
    • @PreDestroy : 在容器移除对象前调用 (bean销毁前通知我们进行销毁清除工作)
    public class BeanClass {
        public BeanClass(){
            System.out.println("Beanclass ... constructor..");
        }
    
        //对象创建并赋值后调用
        @PostConstruct
        public void init(){
            System.out.println("Beanclass ... init ...");
        }
        
        //容器移除对象前
        @PreDestroy
        public void destory(){
            System.out.println("Beanclass .. destory");
        }
    }
    
  • 使用BeanPostProcessor:bean后置处理器

    在bean初始化前后进行一些处理工作

    • postProcessBeforeInitialization : bean初始化前调用该方法
    • postProcessAfterInitialzation :bean初始化后调用该方法
    //后置处理器
    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
        //bean为创建的实例,beanBame为实例在容器中的名字
        //返回bean对象
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("postProcessorBeforeInitialization..."+bean);
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("postProcessAfterInitialization..."+bean);
            return bean;
        }
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BVUlJcHQ-1647083698133)(Java注解.assets/image-20211021213326154.png)]

2.2 BeanPostProcessor运行原理

BeanPostProcessorPostProcessorBeforeInitialization方法设置断点,查看栈运行情况

在这里插入图片描述

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

AnnotationConfigContext.refresh(刷新容器) -> AnnotationConfigContext.finishBeanFactoryInitialization -> docreatBean(repate) -> initializeBean

AbstractAutowireCapableBeanFactory.java执行顺序
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

Spring底层对BeanPostProcessor的使用:如bean赋值,注入其他组件,@Autowired,@Async,生命周期等

3. 属性赋值

3.1 @Value

@Value注解属性赋值的数值类型

  • 基本数值,如数字,字符串等
  • 可以写SpEL表达式,如{};
  • 可以用${},取出配置文件中【properties文件】的值(在运行环境中的值)

spring加载properties后,在创建bean根据@value注解注入properties的值,即使properties有保存起来假如这个对象叫prop,你修改prop的键值,对象中的属性也不会跟着变啊,bean只会初始化拿一次prop中数据,以后都不拿了,就是对象创建好了,就不要想@value这个注解了,改就直接改这个属性呗

3.2 @PropertySource

@PropertySource可以加载外部文件

@PropertySource(value = {"classpath:/配置文件.properties"...})

原理:读取外部文件的key-value值,保存到运行环境的环境变量 中,加载完配置文件后可以使用${}加载外部文件

public class BeanClass {
    @Value("${spring.application.name}")
    private String name;

    @Override
    public String toString() {
        return "BeanClass{" +
                "name='" + name + '\'' +
                '}';
    }
}

@Configuration
@PropertySource(value = {"classpath:name.properties"})
public class AnnotionConfig {



    //默认单实例
    /*
     * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE prototype 单例模式
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON singleton 多例模式
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST 同一个请求加载一次
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION 同一次session加载一次
    */
    @Bean
    public BeanClass bean(){
        return new BeanClass();
    }
}

4. 自动装配

4.1 @Autowired &Qualifier & @Primary

@Autowired自动注入

  • 默认按照类型查找指定组件(通过class获取Bean,ApplicationContext.getBean(bean.claa)

  • 若存在多个同类型的组件,则按属性名作为主键查找(ApplicationContext.getBean("bean_id")注:容器中组件名默认为方法名,若存在多类型且方法名与类名不一致会报错)

  • @Qualifier("指定id"),指定需要装配的组件id

    如使用的组件存在bean1和bean2的同类型,@Autowired按照属性名查找Bean进行装配

  • @Autowired(required = false) 设置自动装配类型允许为空

  • @Primary : 与@Bean搭配使用,让Spring自动装配时,首选该Bean

  • @Bean可以加在方法上或属性上,方法使用的参数和自定义类型的值可以从IOC容器中获取,默认加在IOC中的组件容器先用无参构造器创造对象,再赋值;若标注在有参构造器上,先调用无参构造器再调用有参构造器

@Bean(value = "name_bean")
    public BeanClass bean(ApplicationContext applicationContext){
        System.out.println("-------------->"+applicationContext);
        BeanClass beanClass = new BeanClass();
        beanClass.setName("bean");
        return beanClass;
    }

4.2 @Resource & @Inject

@Resource为JSR250规范,@Inject为JSR330规范

@Resource@Inject都与@Autowired一样可用于自动装配,

  • @Resource(name=“bean_id”)
  • @Inject

4.3 @Profile

@Profile可以作用在方法上或类上,@Profile指定组件在哪个环境下才被注册到容器,若不指定则在任何环境下创建。如:不同环境下使用不同的数据源

@Profile(value="default");//默认值为default

修改环境的方法:

  • 利用命令行参数修改,在VM虚拟机的参数下添加-Dspring.profiles.active="环境"

  • 利用代码方式激活环境

    @Test
        public void ActiveEnvironment(){
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
            applicationContext.getEnvironment().setActiveProfiles("环境");//String[]
            applicationContext.register(MainConfigOfProfile.class);
            applicationContext.refresh();
        }
    

5. AOP

AOP:指能在程序运行期间将某段代码横向切入

JoinPoint:JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数*,就可以获取到封装了该方法信息的*JoinPoint对象

在这里插入图片描述

5.1 AOP的使用

AOP切面编程步骤:

  1. 导入AOP依赖

    		<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
    
    
  2. 编写业务逻辑类和切面类

  3. 在切面类前标注@Aspect标明该类为切面类

    注解说明
    @Before前置通知
    @After后置通知
    @AfterReturning返回通知
    @AfterThrowing异常通知
    @Around环绕通知(动态代理过程,手动推进目标方法运行 )
  4. 标注切面类的目标方法

    • 注解的value使用execution表达式

      如:@Before(execution(public int com.hz.pojo.Calutrtor.*(..)))

    • 使用公共切入点

      如:通过@Before("pointcut()")

      @Pointcut(value = "execution(public int com.hz.pojo.Calutrtor.*(..))")
      public void pointcut(){};//切点
      
  5. 将切面类和业务逻辑类加入容器中

  6. 在容器中添加@EnableAspectJAutoProxy开启AOP支持

//标注该类为一个切面类
@Aspect
public class LogAspects {

    //设置公共切入点
    @Pointcut(value = "execution(public int com.hz.pojo.Calutrtor.*(..))")
    public void pointcut(){};//切点

    //使用公共切入点切入
    @Before(value = "pointcut()")
    public void Before(){
        System.out.println("-----------Before------------");
    }

    @After("pointcut()")
    public void After(){
        System.out.println("-----------After------------");
    }

    @AfterReturning(value = "com.hz.pojo.LogAspects.pointcut()",returning = "result")
    public void AfterReturning(Object result){
        System.out.println("-----------After return :" + result +"------------");
    }

    @AfterThrowing(value = "pointcut()",throwing="exception")
    public void AfterThrowing(JoinPoint joinPoint,Exception exception){
        System.out.println("-----Throw"+joinPoint.getSignature().getName()+"Exception:"+exception+"--------");
    }

}
//开启AOP支持
@EnableAspectJAutoProxy
public class AOP_Config {

    @Bean
    public Calutrtor calututor(){
        return new Calutrtor();
    }

    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}

5.2 AOP原理

5.2.1 @EnableAspectAutoProxy

AOP支持开启注解@EnableAspectJAutoProxy

EnableAspectJAutoProxy接口继承关系

在这里插入图片描述

利用AspectJAutoProxyRegistrar给容器注册Bean

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

   /**
    * Register, escalate, and configure the AspectJ auto proxy creator based on the value
    * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
    * {@code @Configuration} class.
    */
   @Override
   public void registerBeanDefinitions(
         AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

      AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

      AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
      if (enableAspectJAutoProxy != null) {
         if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
         }
         if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
         }
      }
   }
}

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

debug跟踪到

AnnotationAwareAspectJAutoProxyCreator创建BeanDefination

private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}

		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

在这里插入图片描述

如下图,AnnotationAwareAspectJAutoProxyCreator的父类继承中包含SmartInstantiationAwareBeanPostProcessor后置处理器和BeanFactoryAware感知器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TXAP9hg1-1647083698136)(Java注解.assets/image-20211030150042991.png)]

后置处理器:在Bean初始化前后做的事由后置处理器处理

Debug分析

  1. 传入配置类,创建IOC容器

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

  3. 调用registerBeanPostProcessors(beanFactory) 注册Bean后置处理器来拦截Bean的创建

    1. 获取IOC容器中的所有后置处理器

      List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
      		for (String ppName : orderedPostProcessorNames) {
      			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      			orderedPostProcessors.add(pp);
      			if (pp instanceof MergedBeanDefinitionPostProcessor) {
      				internalPostProcessors.add(pp);
      			}
      		}
      		sortPostProcessors(orderedPostProcessors, beanFactory);
      		registerBeanPostProcessors(beanFactory, orderedPostProcessors);
      
      		// Now, register all regular BeanPostProcessors.
      		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
      		for (String ppName : nonOrderedPostProcessorNames) {
      			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      			nonOrderedPostProcessors.add(pp);
      			if (pp instanceof MergedBeanDefinitionPostProcessor) {
      				internalPostProcessors.add(pp);
      			}
      		}
      		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-It9TfMvr-1647083698136)(Java注解.assets/image-20211030153728189.png)]

    2. 给容器中加别的BeanPostProcessor后置处理器

    3. 优先注册BeanOrdered接口的BeanPosrProcessor,再注册Ordered接口的BeanPostProcessor,

      ,再注册剩余的BeanPostProcessor

      1. 创建Bean
      2. populateBean:给Bean的各属性赋值
      3. initializeBean:初始化Bean
        1. invokeAwareMethods:处理Aware方法回调
        2. postProcessBeforeInitialization : 前置处理器初始化
        3. invokeInitMethods : 执行初始化方法
        4. applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName):后置处理器初始化
    4. BeanPostProcessor注册到BeanFactory

    AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor

    不同于BeanPostProcessor

    在这里插入图片描述

    ​ Bean创建与实例化流程

    1. finishBeanFactoryInitialization(beanFactory); 完成BeanFactory的初始化工作

      1. 遍历所有Bean,以此创建Bean

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3jdlvfo-1647083698138)(Java注解.assets/image-20211030161840681.png)]

      2. doGetBean 创建Bean(先查找缓存中是否存在对应Bean,如果存在注解使用,如果不存在再创建Bean实例)

      3. CreateBean 创建Bean代理resolveBeforeInstantiation

        protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        		for (BeanPostProcessor bp : getBeanPostProcessors()) {
        			if (bp instanceof InstantiationAwareBeanPostProcessor) {
        				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
        				if (result != null) {
        					return result;
        				}
        			}
        		}
        		return null;
        	}
        
      4. doCreateBean : 真正创建Bean实例

5.2.2 AOP流程

  1. 在Bean创建前,调用postProcessBeforeInstantiation创建

    1. 判断Bean是否在advisedBeans(保存了所有需要增强的Bean)

    2. 判断当前Bean是否为基础类型的Bean(Advice,Pointcut,Advisor等)或者是否是切面

      protected boolean isInfrastructureClass(Class<?> beanClass) {
         boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
               Pointcut.class.isAssignableFrom(beanClass) ||
               Advisor.class.isAssignableFrom(beanClass) ||
               AopInfrastructureBean.class.isAssignableFrom(beanClass);
         if (retVal && logger.isTraceEnabled()) {
            logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
         }
         return retVal;
      }
      
    3. 是否需要跳过

      1. 获取候选增强器candidateAdvisors,判断每个增强器是否为ASpectJPointAdvisor类型,是的话返回true
      2. 返回false
  2. 创建PostProvessorAfterInitialization

    1. 获取当前Bean的所有增强器
      1. 获取能在当前Bean使用的增强器
      2. 对增强器排序
    2. 保存当前Bean到AdvisedBeans中
    3. 如果当前Bean需要加强,需要则创建代理对象
      1. 保存到proxyFactory
      2. 创建代理对象:Spring决定
    4. 给容器中返回组件使用cglib加强了的代理对象
    5. 以后容器中获取的为代理对象
  3. 目标方法执行(责任链模式)

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

    1. ClibAopProxy.intercept(); //拦截方法执行
    2. 根据ProxyFactory获取将要执行的方法
    3. 如果没有拦截器链,直接执行目标方法
    4. 如果不是,则将执行的目标对象,目标方法,连接器等信息,创建一个CglibMethodInvocation对象
    5. 拦截器链子触发过程

    在这里插入图片描述

6. 声明型事务

声明型事务:在编程中,每个sql语句执行完并提交称为一个事务,声明型事务对每个方法加上事务注解,通知Sping该方法为一个事务,但该方法执行完并没有任何问题则提交事务,若过程中出现错误,则该sql语句不执行,回到原来状态。

使用方法:

  1. 导入依赖(数据源,数据库驱动,spring-jdbc模块)

    <!--jdbc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <!--Mybatis-plus依赖-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.2.0</version>
            </dependency>
    
  2. 配置数据源(Springboot自动配置数据源通过@Autowired加载)

    @Autowired
    DataSource dataSource;
    @Autowired
    JdbcTemplate jdbcTemplate;
    
  3. 编写Dao类,在事务型方法上标注上@Transactional

    @Repository
    public class UserDao {
        @Autowired
        JdbcTemplate jdbcTemplate;
    
        @Transactional
        public List<Map<String,Object>> search(){
            String sql = "select * from `user`";
            List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
            return maps;
        }
    }
    
  4. 在运行类上标注@EnableTransactionManagement

  5. 注册事务管理器在容器中

    @Configuration
    public class TransactionMangerConfig {
    
        @Autowired
        DataSource dataSource;
        
        @Bean
        public PlatformTransactionManager transactionManager(){
            return new DataSourceTransactionManager(dataSource);
        }
    }
    

7.拓展原理

7.1 BeanFactoryPostProcessor

BeanFactoryPostProcessorBeanFactory的后置处理器,在BeanFactory初始化前后调用,即所有Bean被加载到BeanFactory

BeanFactoryPostProcessor的创建过程:

  1. ioc容器创建对象
  2. invokeBeanPostProcessor执行BeanPostProcessor
    1. 直接在BeanFActory中找出所有BeanFactoryPostProcessor并执行方法
    2. 在初始化,创建其他组件前面执行
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        for (String s : beanDefinitionNames) {
            System.out.println(s);
        }
    }
}

7.2 BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()

在所有Bean定义信息都被加载,bean实例还未创建之前

  1. ioc容器创建对象
  2. refresh() - > invokeBeanFactoryPostProcessor(beanFactory)
  3. 从容器中获取所有BeanDefinitionRegistryPostProcessor依次触发postProcessorBeanFactory;
@Component
public class MyPostProcessBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {

    //BeanDefinitionRegistry的信息进行BeanFactory的创建
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("BeanDefinitopnregistry...bean的数量:"+registry.getBeanDefinitionCount());
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(BeanClass.class);
        registry.registerBeanDefinition("bean2", rootBeanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("BeanDefinitopn...bean的数量:"+beanFactory.getBeanDefinitionCount());
    }
}
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        System.out.println("postProcessBeanFactory...bean的数量:"+beanFactory.getBeanDefinitionCount());
    }
}

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RKAlh9vH-1647083698140)(Java注解.assets/image-20211106100102619.png)]

7.3 ApplicationListener

ApplicationListener : 监听容器中发布的事件,事件驱动模型开发

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener监听ApplicationEvent及其下面的子事件:

步骤:

  1. 写一个监听器监听某个事件(ApplicationEvent及其子类)

  2. 把监听器添加到容器中

  3. 只要容器中相关事件的发布,我们就能监听到这个事件:

    ContextRefreshedEvent:容器刷新完成(所有Bean都完全创建)会发布这个事件

    ContextClosedEvent:关闭这个容器会发布事件

  4. 发布一个事件

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("事件--------------->"+event);
    }
}

原理:

  1. 容器创建对象,refresh()刷新

  2. finishRefresh 容器刷新完成

  3. publishEvent(new ContextRefreshedEvent(this))

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SH2Z9S2H-1647083698141)(Java注解.assets/image-20211106104101422.png)]

    事件发布流程:

    1. 获取事件的多播器(派发器)

    2. multicastEvent派发事件

      public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
         ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
         Executor executor = getTaskExecutor();
         for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
               executor.execute(() -> invokeListener(listener, event));
            }
            else {
               invokeListener(listener, event);
            }
         }
      }
      
    3. 获取到所有的ApplicationListener(如果有Executor则可以支持使用Executor进行异步派发,否则直接执行同步的同步Listener方法)

在这里插入图片描述

多播器获取方法:initApplicationEventMulticaster();AbstractApplicationContext

protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isTraceEnabled()) {
         logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }
   else {
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
               "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
      }
   }
}

7.4 @EventListener

@EventListener(classes = {ApplicationEvent.class})
public void init(ApplicationEvent event){
    System.out.println("-----事件----"+event);
}

SmartInitializingSingleton

finishBeanFactoryInitialization(beanFactory);
beanFactory.preInstantiateSingletons();
ter() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isTraceEnabled()) {
         logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }
   else {
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
               "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
      }
   }
}

7.4 @EventListener

@EventListener(classes = {ApplicationEvent.class})
public void init(ApplicationEvent event){
    System.out.println("-----事件----"+event);
}

SmartInitializingSingleton

finishBeanFactoryInitialization(beanFactory);
beanFactory.preInstantiateSingletons();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值