Spring源码解析【完整版】--【bilibili地址:https://www.bilibili.com/video/BV1oW41167AV】

【本文为bilibili视频Spring源码解析的完整版总结文章,其中文章前面大部分为他人博文的搬运,后面补充了其未总结的部分】一、Java中的注解二、Spring中的注解三、AOP原理四、Spring事务控制五、扩展原理六、Spring容器创建
摘要由CSDN通过智能技术生成

【本文为bilibili视频雷丰阳的Spring源码解析的完整版总结文章,其中文章前面大部分为他人博文的搬运,后面补充了其未总结的部分】

一、Java的注解

1. 注解的概念

注释:用文字描述程序,给程序员看的;

注解:说明程序的,给计算机看的。

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

概念描述:

  • JDK1.5之后的新特性
  • 说明程序的
  • 使用注解:@注解名称

作用分类:

  1. 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
/**
 1. 注解javadoc演示
 2.  3. @version 1.0
 4. @since 1.5
 */
public class AnnoDemo1 {
   

    /**
     * 计算两数的和
     * @param a 整数
     * @param b 整数
     * @return 两数的和
     */
    public int add(int a, int b ){
   
        return a + b;
    }
}
  1. 代码分析:通过代码里表示的注解对代码进行分析【使用反射】
  2. 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【@Override】

JDK中预定义的一些注解:

  • @Override:检测被该注解标注的方法是否是继承自父类(接口)的
  • @Deprecated:该注解标注的内容,表示已过时
  • @SuppressWarnings:压制警告。一般传递参数all,@SuppressWarnings("all")

2. 自定义注解

格式:

public @interface 注解名称{
   
	属性列表;
}

本质:注解本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation {}

属性:接口中的抽象方法
属性的返回值值类型有如下取值:

  • 基本数据类型
  • String
  • 枚举
  • 注解
  • 以上类型数组
 public @interface MyAnno {
   
    int value();
    Person per();
    MyAnno2 anno2();
    String[] strs();
    String name() default "张三";
}

定义了属性,在使用时需要给属性赋值:

  1. 如果定义属性时,使用default关键字给属性默认初始值,则在使用注解,可以不进行属性的赋值;
  2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以忽略,直接定义值即可;
  3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略。
@MyAnno(value=12, per = Person.P1, anno2 = @MyAnno2, strs="bbb")
public class Worker {
   
}

3. 元注解

元注解: 用于描述注解的注解

  • @Target:描述注解能够给作用的位置。

  • ElementType取值:

    • TYPE:可以作用于类上
    • METHOD:可以作用于方法上
    • FIELD:可以作用于成员变量上
  • @Retention:描述注解被保留的阶段

    value 是 java.lang.annotation.RetentionPolicy 枚举类型, RetentionPolicy 有 3 个枚举常量,如下所示:

    • SOURCE:在源文件中有效(即源文件保留)
    • CLASS:在 class 文件中有效(即 class 保留)
    • RUNTIME:在运行时有效(即运行时保留)
      @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到。
  • @Documneted:描述注解是否被抽取到API文档中

  • @Inherited:描述注解是否被子类继承

@Target({
   ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnno3 {
   
}

@MyAnno3
public class Worker {
   
    @MyAnno3
    public String name = "aaa";
    @MyAnno3
    public void show(){
   
    }
}

4. 注解解析

在程序使用(解析)注解:获取注解中定义的属性值。

@Pro(className = "top.tjtulong.annotation.Demo1",methodName = "show")
public class ReflectTest {
   
    public static void main(String[] args) throws Exception {
   
        Pro an = reflectTestClass.getAnnotation(Pro.class);
        // 调用注解对象中定义的抽象方法,获取返回值
        String className = an.className();
        String methodName = an.methodName();
        System.out.println(className);
        System.out.println(methodName);
    }
}
  1. 获取注解定义的位置上的对象(Class, Method, Field);
  2. 获取指定的注解:getAnnotation(Class),其实就是在内存中生成了一个该注解接口的子类实现对象。
public class ProImpl implements Pro{
   
    public String className(){
   
        return "top.tjtulong.annotation.Demo1";
    }
    
    public String methodName(){
   
        return "show";
    }
}	

  1. 调用注解中的抽象方法获取配置的属性值

二、Spring中的注解

1. 组件注册

@Configuration:指定配置类;

@Component:用于把当前类对象存入spring容器中;

以下三个注解的作用与@Component完全一样,它们是spring提供的更明确的划分,使三层对象更加清晰:

  • @Controller:用于表现层;
  • @Service:用于业务层;
  • @Repository:用于持久层;

@Bean:给容器中注册一个Bean对象,类型为返回值的类型,id默认是用方法名作为id;

@ComponentScan:指明注解扫描的包,属性包括:

  • excludeFilters = Filter[] :指定扫描的时候按照什么规则排除哪些组件,通过@Filter() 来具体指定
  • includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件(同时需要配置userDefaultFilters=false,才能生效)
    • FilterType.ANNOTATION:按照注解类型过滤

    • FilterType.ASSIGNABLE_TYPE:按照给定的类型过滤

    • FilterType.ASPECTJ:使用ASPECTJ表达式过滤

    • FilterType.REGEX:使用正则指定

    • FilterType.CUSTOM:使用自定义规则过滤

        原先使用bean.xml配置时,还需先将默认属性设置成 use-defalut=false ,即禁用默认扫描规则。
      

@ComponentScans:指明多个@ComponentScan扫描的包;

@Scope:调整Bean实例的作用域,共有4种:

  • prototype:多实例的,ioc容器启动并不会去调用方法创建对象放在容器中,而是每次获取的时候才会调用方法创建对象
  • singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器中拿(map.get);
  • request:同一次请求创建一个实例;
  • session:同一个session创建一个实例。

@Lazy:懒加载,容器启动不创建对象(抑制了singleton原本的加载方式),第一次获取Bean时再创建对象并初始化;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.ComponentScans;

import top.tjtulong.bean.Person;

// 配置类==配置文件
@Configuration  // 告诉Spring这是一个配置类
@ComponentScans(
    value = {
   
        @ComponentScan(value="top.tjtulong",includeFilters = {
   
            @Filter(type=FilterType.ANNOTATION, classes={
   Controller.class}),
            @Filter(type=FilterType.ASSIGNABLE_TYPE, classes={
   BookService.class}),
            @Filter(type=FilterType.CUSTOM, classes={
   MyTypeFilter.class})
		},useDefaultFilters = false)	
    }
)
public class MainConfig {
   
	//给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id
    @Scope("prototype")
	@Bean("person")
	public Person person01(){
   
		return new Person("lisi", 20);
	}
}

public class Person {
   
	private String name;
    
	private Integer age;	
	
    //get() set() toString()...	
}

自定义的包扫描过滤规则

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;
	}
}

@Condition:按照一定的条件进行判断,满足条件给容器中注册bean,可以放在类上,也可以放在方法上;

@Import:导入组件,id默认是 组件的全类名

//类中组件统一设置,满足当前条件,这个类中配置的所有bean注册才能生效;
// @Conditional({WindowsCondition.class})
@Configuration
// MyImportSelector:自定义导入逻辑
// @Import({Color.class, Red.class, MyImportSelector.class}) 
@Import({
   Color.class, Red.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {
   
    /**
	 * 如果系统是windows,给容器中注册("bill")
	 * 如果是linux系统,给容器中注册("linus")
	 */	
	@Conditional({
   WindowsCondition.class})
	@Bean("bill")
	public Person person01(){
   
		return new Person("Bill Gates",62);
	}
	
	@Conditional({
   LinuxCondition.class})
	@Bean("linus")
	public Person person02(){
   
		return new Person("linus", 48);
	}
}

Condition 类:

//判断是否linux系统
public class LinuxCondition implements Condition {
   

	/**
	 * ConditionContext:判断条件能使用的上下文(环境)
	 * AnnotatedTypeMetadata:注释信息
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
   
		// TODO是否linux系统
		//1、能获取到ioc使用的beanfactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//2、获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//3、获取当前环境信息
		Environment environment = context.getEnvironment();
		//4、获取到bean定义的注册类
		BeanDefinitionRegistry registry = context.getRegistry();
		//可以判断容器中的Bean注册情况,也可以给容器中注册bean
		boolean definition = registry.containsBeanDefinition("person");
		
		String property = environment.getProperty("os.name");
		if(property.contains("linux")){
   
			return true;
		}
		return false;
	}
}

实现ImportSelector 自定义逻辑导入需要的组件

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
   
    
    //返回值,就是要导入到容器中的组件的全类名
    //AnnotationMetadata:当前标注 @Import 注解的类的所有注解信息
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
   
        
        //默认不要返回null
        //全类名
        return new String[]{
   "com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
    }
}

实现 ImportBeanDefinitionRegistrar 手动注册bean到容器中:

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
   

	/**
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:BeanDefinition注册类;
	 * 		把所有需要添加到容器中的bean;
	 * 		调用BeanDefinitionRegistry.registerBeanDefinition手工注册进来
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   
		
		boolean definition = registry.containsBeanDefinition("top.tjtulong.bean.Red");
		boolean definition2 = registry.containsBeanDefinition("top.tjtulong.bean.Blue");
		if(definition && definition2){
   
			//指定Bean定义信息
			//RootBeanDefinition 为接口BeanDefintion的实现
			RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
			//注册一个Bean,指定bean名
			registry.registerBeanDefinition("rainBow", beanDefinition);
		}
	}
}

给容器中注册组件方法汇总:

  1. 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
  2. @Bean[导入的第三方包里面的组件]
  3. @Import[快速给容器中导入一个组件]
    1. @Import(要导入到容器中的类);容器中就会自动注册这个组件,id默认是全类名;
    2. ImportSelector:返回需要导入的组件的全类名数组;
    3. ImportBeanDefinitionRegistrar:手动注册bean到容器中;
  4. 使用Spring提供的FactoryBean(工厂Bean);
    1. 默认获取到的是工厂bean调用getObject()创建的对象;
    2. 要获取工厂Bean本身,需要给id前面加一个&(&colorFactoryBean); 否则,获取的是getObject()方法返回值对象。
@Bean
public ColorFactoryBean colorFactoryBean(){
   
	//返回的虽然是colorFactoryBean,但其为com.titjlong.bean.Color类型
	//工厂bean的获取最终会调用getObject(),以其返回值类型为准
    return new ColorFactoryBean();
}

//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
   

	//返回一个Color对象,这个对象会添加到容器中
	@Override
	public Color getObject() throws Exception {
   
		System.out.println("ColorFactoryBean...getObject...");
		return new Color();
	}

	@Override
	public Class<Color> getObjectType() {
   
		return Color.class;
	}

	//是否为单例
	@Override
	public boolean isSingleton() {
   
		return false;
	}
}

2. 生命周期

bean 的生命周期是指:bean的创建 ---> 初始化 ---> 销毁的过程

方法一:通过@Bean指定初始化和销毁方法

initMethod:初始化方法;destroyMethod:销毁方法。

@Component
public class Car {
   
	
	public Car(){
   
		System.out.
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值