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. 组件注册
-
包扫描+组件标注注解(@Controller/@Service/@Repository/@Component/)(仅限自己写的)
-
@Bean 导入第三方的组件
-
@Import (快速给容器一个组件)
-
@Import({导入的组件类.class…}),容器会自动注册这个组件,id默认是全类名
-
@ImportSelector:返回导入到容器中的组件的全类名数组(不能返回null)
@Import(@MyImportSelector.class)
-
@ImportBeanDefinitionRegistrar 手动注册组件
-
-
spring的FactoryBean创建Bean(工厂Bean)
- 默认获取的bean为工厂创建的对象,返回工厂对象用
&FactoryBean
- 默认获取的bean为工厂创建的对象,返回工厂对象用
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指定初始化和销毁
-
springmvc
中Bean
的初始化与销毁,通过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运行原理
在BeanPostProcessor
的PostProcessorBeforeInitialization
方法设置断点,查看栈运行情况
@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切面编程步骤:
-
导入AOP依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
编写业务逻辑类和切面类
-
在切面类前标注
@Aspect
标明该类为切面类注解 说明 @Before 前置通知 @After 后置通知 @AfterReturning 返回通知 @AfterThrowing 异常通知 @Around 环绕通知(动态代理过程,手动推进目标方法运行 ) -
标注切面类的目标方法
-
注解的
value
使用execution表达式如:
@Before(execution(public int com.hz.pojo.Calutrtor.*(..)))
-
使用公共切入点
如:通过
@Before("pointcut()")
@Pointcut(value = "execution(public int com.hz.pojo.Calutrtor.*(..))") public void pointcut(){};//切点
-
-
将切面类和业务逻辑类加入容器中
-
在容器中添加
@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分析
-
传入配置类,创建IOC容器
-
注册配置类,调用refresh()刷新容器
-
调用
registerBeanPostProcessors(beanFactory)
注册Bean后置处理器来拦截Bean的创建-
获取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)]
-
给容器中加别的BeanPostProcessor后置处理器
-
优先注册BeanOrdered接口的BeanPosrProcessor,再注册Ordered接口的BeanPostProcessor,
,再注册剩余的BeanPostProcessor
- 创建Bean
- populateBean:给Bean的各属性赋值
- initializeBean:初始化Bean
- invokeAwareMethods:处理Aware方法回调
- postProcessBeforeInitialization : 前置处理器初始化
- invokeInitMethods : 执行初始化方法
- applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName):后置处理器初始化
-
把
BeanPostProcessor
注册到BeanFactory
中
AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor
不同于BeanPostProcessor
Bean创建与实例化流程
-
finishBeanFactoryInitialization(beanFactory); 完成BeanFactory的初始化工作
-
遍历所有Bean,以此创建Bean
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3jdlvfo-1647083698138)(Java注解.assets/image-20211030161840681.png)]
-
doGetBean 创建Bean(先查找缓存中是否存在对应Bean,如果存在注解使用,如果不存在再创建Bean实例)
-
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; }
-
doCreateBean : 真正创建Bean实例
-
-
5.2.2 AOP流程
-
在Bean创建前,调用
postProcessBeforeInstantiation
创建-
判断Bean是否在
advisedBeans
(保存了所有需要增强的Bean) -
判断当前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; }
-
是否需要跳过
- 获取候选增强器
candidateAdvisors
,判断每个增强器是否为ASpectJPointAdvisor类型,是的话返回true - 返回false
- 获取候选增强器
-
-
创建
PostProvessorAfterInitialization
- 获取当前Bean的所有增强器
- 获取能在当前Bean使用的增强器
- 对增强器排序
- 保存当前Bean到AdvisedBeans中
- 如果当前Bean需要加强,需要则创建代理对象
- 保存到proxyFactory
- 创建代理对象:Spring决定
- 给容器中返回组件使用cglib加强了的代理对象
- 以后容器中获取的为代理对象
- 获取当前Bean的所有增强器
-
目标方法执行(责任链模式)
容器中保存了组件的代理对象(cglib增强后的对象),这个对象保存了详细信息(比如增强器,目标对象等)
- ClibAopProxy.intercept(); //拦截方法执行
- 根据ProxyFactory获取将要执行的方法
- 如果没有拦截器链,直接执行目标方法
- 如果不是,则将执行的目标对象,目标方法,连接器等信息,创建一个
CglibMethodInvocation
对象 - 拦截器链子触发过程
6. 声明型事务
声明型事务:在编程中,每个sql语句执行完并提交称为一个事务,声明型事务对每个方法加上事务注解,通知Sping该方法为一个事务,但该方法执行完并没有任何问题则提交事务,若过程中出现错误,则该sql语句不执行,回到原来状态。
使用方法:
-
导入依赖(数据源,数据库驱动,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>
-
配置数据源(
Springboot
自动配置数据源通过@Autowired
加载)@Autowired DataSource dataSource; @Autowired JdbcTemplate jdbcTemplate;
-
编写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; } }
-
在运行类上标注
@EnableTransactionManagement
-
注册事务管理器在容器中
@Configuration public class TransactionMangerConfig { @Autowired DataSource dataSource; @Bean public PlatformTransactionManager transactionManager(){ return new DataSourceTransactionManager(dataSource); } }
7.拓展原理
7.1 BeanFactoryPostProcessor
BeanFactoryPostProcessor
为BeanFactory
的后置处理器,在BeanFactory
初始化前后调用,即所有Bean被加载到BeanFactory
BeanFactoryPostProcessor
的创建过程:
- ioc容器创建对象
invokeBeanPostProcessor
执行BeanPostProcessor
- 直接在
BeanFActory
中找出所有BeanFactoryPostProcessor
并执行方法 - 在初始化,创建其他组件前面执行
- 直接在
@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实例还未创建之前
- ioc容器创建对象
- refresh() - > invokeBeanFactoryPostProcessor(beanFactory)
- 从容器中获取所有
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及其下面的子事件:
步骤:
-
写一个监听器监听某个事件(ApplicationEvent及其子类)
-
把监听器添加到容器中
-
只要容器中相关事件的发布,我们就能监听到这个事件:
ContextRefreshedEvent:容器刷新完成(所有Bean都完全创建)会发布这个事件
ContextClosedEvent:关闭这个容器会发布事件
-
发布一个事件
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("事件--------------->"+event);
}
}
原理:
-
容器创建对象,refresh()刷新
-
finishRefresh 容器刷新完成
-
publishEvent(new ContextRefreshedEvent(this))
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SH2Z9S2H-1647083698141)(Java注解.assets/image-20211106104101422.png)]
事件发布流程:
-
获取事件的多播器(派发器)
-
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); } } }
-
获取到所有的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();