Spring源码日常笔记(一)

Spring源码日常笔记(一)

学习Spring源码太枯燥,看着看着就想睡觉,为了让自己不睡觉,一边学习一边记录下学习的过程,有错误的地方望大佬亲喷.(看的是享学课堂james老师讲的,若有侵权,必删)

初识Spring

Spring是一种开源轻量级框架,是为了解决企业应用程序开发复杂性而创建的,Spring致力于解决JavaEE的各层解决方案,而不仅仅于某一层的方案。
2003年2月Spring框架正式称为一道开源项目,Spring致力于J2EE应用的各种解决方案,而不仅仅专注于某一层解决方案。可以说Spring是企业应用开发的“一站式”选择, Spring贯穿于表现层、业务层、持久层,然而Spring并不想取代那些已经有的框架,而是以高度的开放性,与这些已有的框架进行整合。

Spring的优点

1、让现有的技术更容易使用,
2、促进良好的编程习惯。
Spring是一个全面的解决方案,它坚持一个原则:不从新造轮子。已经有较好解决方案的领域,Spring绝不重复性实现,比如:对象持久化和OR映射,Spring只对现有的JDBC,Hibernate等技术提供支持,使之更容易使用,而不做重复的实现。Spring框架有很多特性,这些特性由7个定义良好的模块构成。
1、 Spring Core:即,Spring核心,它是框架最基础的部分,提供IOC和依赖注入特性
2、 Spring Context:即,Spring上下文容器,它是BeanFactory功能加强的一个子接口
3、 Spring Web:它提供Web应用开发的支持
4、 Spring MVC:它针对Web应用中MVC思想的实现
5、 Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性。
6、 Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO的整合等等。
7、 Spring AOP:AOP即,面向切面编程,它提供了与AOP联盟兼容的编程实现

Spring的常用组件

Spring的初体验

1 创建maven工程
2 导入spring-context依赖

<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>5.0.6.RELEASE</version>
</dependency>

3.1(xml方式)
(1) 创建bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="person" class="com.enjoy.cap1.Person">
  	<property name="name" value="james"></property>
  	<property name="age" value="19"></property>
  </bean>
</beans>

(2) 新建person.java

public class Person {
   private String name;
   private Integer age;
   
   public Person(){
   	super();
   }
   public String getName() {
   	return name;
   }
   public void setName(String name) {
   	this.name = name;
   }
   public Person(String name, Integer age) {
   	super();
   	this.name = name;
   	this.age = age;
   }
   public Integer getAge() {
   	return age;
   }
   @Override
   public String toString() {
   	return "Person [name=" + name + ", age=" + age + "]";
   }
   public void setAge(Integer age) {
   	this.age = age;
   }
}

(3) 测试类

public class MainTest1 { 
   public static void main(String args[]){
   	//把beans.xml的类加载到容器
   	ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
   	//从容器中获取bean
   	Person person = (Person) app.getBean("person");
   	
   	System.out.println(person);
   }
}

控制台输出:
Person [name=james, age=19]

3.2(注解方式)
如果我们用注解开发, 很明显是不需要XML的,3.1方法中bean.xml可删除.

(1) 使用@Configuration 和 @Bean注解,@Bean注解可以定义bean的name,如下:

@Configuration
public class MainConfig {
  //给容器中注册一个bean, 类型为返回值的类型, 
  @Bean("abcPerson")
  public Person person01(){
  	return new Person("james",20);
  }
}

(2) 测试一下

public class MainTest2 { 
  public static void main(String args[]){
  	//把beans.xml的类加载到容器
  	
  	ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
  	String[] namesForBean = app.getBeanNamesForType(Person.class);
  	for(String name:namesForBean){
  		System.out.println(name);
  	}
  }
}

控制台输出:
abcPerson

Spring @ComponentScan注解扫描规则

(1) 简单使用:

@Configuration
@ComponentScan(value="com.enjoy.cap2")
public class Cap2MainConfig {
	//给容器中注册一个bean, 类型为返回值的类型, 
	@Bean
	public Person person01(){
		return new Person("james",20);
	}
}

@ComponentScan(value=“com.enjoy.cap2”)表示扫描com.enjoy.cap2下的包
com.enjoy.cap2包下结构如下:
controller,service,dao下都加了@Controller,@service,@Respostry注解,让ComponentScan能扫描到.
在这里插入图片描述
测试类:

public class Cap2Test {
    public static void main(String[] args) {
        ApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
        String[] beanDefinitionNames = app.getBeanDefinitionNames();
        for(String s : beanDefinitionNames){
            System.out.println(s);
        }
    }
}

控制台输出:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cap2MainConfig
orderController
orderDao
orderService
person01

(2) 定制包扫描时的过滤规则
新建dao, service,controller,如下图
Controller
Dao
Service
在Cap2MainConfig2 @ComponentScan注解中加入配置: @Filter: 扫描规则

@Configuration
//@Controller  @Service  @Respostry  @Component
@ComponentScan(value="com.enjoy.cap2", includeFilters={
		@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),		
		@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class})
}, useDefaultFilters=false)//默认是true,扫描所有组件,要改成false,使用自定义扫描范围
public class Cap2MainConfig {
	//给容器中注册一个bean, 类型为返回值的类型, 
	@Bean
	public Person person01(){
		return new Person("james",20);
	}
}

ComponentScan 下属性的意思
@ComponentScan value:指定要扫描的包
excludeFilters = Filter[] 指定扫描的时候按照什么规则排除那些组件
includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件
useDefaultFilters = false 默认是true,扫描所有组件,要改成false
----扫描规则如下
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按BookService类型
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:使用正则指定
FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口

这里使用FilterType.ANNOTATION的例子遇到一个问题,如下:
配置类:

@Configuration
//@Controller  @Service  @Respostry  @Component
@ComponentScan(value="com.enjoy.cap2", excludeFilters={
		@Filter(type=FilterType.ANNOTATION, classes={Controller.class})
}, useDefaultFilters=false)
public class Cap2MainConfig {
	//给容器中注册一个bean, 类型为返回值的类型, 
	@Bean
	public Person person01(){
		return new Person("james",20);
	}
}

com.enjoy.cap2结构如下:
在这里插入图片描述
我们使用测试类测试:

public class Cap2Test {

    public static void main(String[] args) {
        ApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
        String[] beanDefinitionNames = app.getBeanDefinitionNames();
        for(String s : beanDefinitionNames){
            System.out.println(s);
        }
    }
}

我们理想输出的结果应该是:
cap2MainConfig
orderDao
orderService
person01
将Controller排除掉

但是现实输出的结果是:
cap2MainConfig
person01
将Controller,Service,Dao都排除掉了

这是为什么呢,好像跟我们想的有点误差:
(1)@componentScan会交给Scanorg.springframework.context.config.ContextNamespaceHandler这个类处理.

registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());

(2)ComponentScanBeanDefinitionParser会读取配置文件信息并组装成org.springframework.context.annotation.ClassPathBeanDefinitionScanner进行处理。
(3)如果没有配置@ComponentScan的use-default-filters属性,则默认为true,在创建ClassPathBeanDefinitionScanner时会根据use-default-filters.
如果为true,会调用registerDefaultFilters方法.我们这边设置use-default-filters为true,
会调用registerDefaultFilters方法.
具体实现如下:

protected void registerDefaultFilters() {
	//Component注解会默认把Controller,Service,Repository注解都扫描进来.
  this.includeFilters.add(new AnnotationTypeFilter(Component.class));
  ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
  try {
    this.includeFilters.add(new AnnotationTypeFilter(
      ((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
    logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
  }
  catch (ClassNotFoundException ex) {
    // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
  }
  try {
    this.includeFilters.add(new AnnotationTypeFilter(
      ((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
    logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
  }
  catch (ClassNotFoundException ex) {
    // JSR-330 API not available - simply skip.
  }
}

(4)在进行扫描时会通过include-filter/exclude-filter来判断你的Bean类是否是合法的:

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
 for (TypeFilter tf : this.excludeFilters) {
   if (tf.match(metadataReader, this.metadataReaderFactory)) {
      return false;
   }
 }
 for (TypeFilter tf : this.includeFilters) {
   if (tf.match(metadataReader, this.metadataReaderFactory)) {
      AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
      if (!metadata.isAnnotated(Profile.class.getName())) {
         return true;
      }
      AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
      return this.environment.acceptsProfiles(profile.getStringArray("value"));
    }
  }
 return false;
}

扫描时首先通过exclude-filter 进行黑名单过滤,然后通过include-filter 进行白名单过滤,否则默认排除。

下面举一个FilterType.CUSTOM的例子(常用)
先新增自定义过滤规则类:(name中包含"order"扫描进来)

public class JamesTypeFilter implements TypeFilter{
	private ClassMetadata classMetadata;

	/*
	 * MetadataReader:读取到当前正在扫描类的信息
	 * MetadataReaderFactory:可以获取到其他任何类信息
	 */
	
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		//获取当前类注解的信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		//获取当前正在扫描的类信息
		classMetadata = metadataReader.getClassMetadata();
		//获取当前类资源(类的路径)
		Resource resource = metadataReader.getResource();
		
		String className = classMetadata.getClassName();
		System.out.println("----->"+className);
		if(className.contains("Order")){//当类包含order字符, 则匹配成功,返回true
			return true;
		}
		return false;
	}
}

在Cap2MainConfig申明:

@ComponentScan(value="com.enjoy.cap2",includeFilters={
		@Filter(type=FilterType.CUSTOM,classes={JamesTypeFilters.class})
},useDefaultFilters=false) 
public class Cap2MainConfig2 {
	@Bean
	public Person person01(){
		return new Person("james",20);
	}
}

打印结果:
----->com.enjoy.cap2.Cap2Test
----->com.enjoy.cap2.config.JamesTypeFilter
----->com.enjoy.cap2.controller.OrderController
----->com.enjoy.cap2.dao.OrderDao
----->com.enjoy.cap2.service.OrderService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cap2MainConfig
orderController
orderDao
orderService
person01

scope扫描规则

  1. 新建Cap3MainConfig.java
@Configuration
public class Cap3MainConfig {
	//给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
	/*
	 * prototype:多实例: IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
	 * singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿(大Map.get)的同一个bean
	 * request: 主要针对web应用, 递交一次请求创建一个实例
	 * session:同一个session创建一个实例
	 */
	@Bean
	public Person person(){
		//默认为单例
		return new Person("james",20);
	}
}

//单例只会被实例化一次

多例的情况下添加@Scope注解:

@Configuration
public class Cap3MainConfig {
	@Scope("prototype")
	@Bean
	public Person person(){
		return new Person("james",20);
	}
}

注:
prototype: 多实例:IOC容器启动并不会去调用方法创建对象放在容器中,而是 每次获取的时候才会调用方法创建对象,见test02
singleton: 单实例(默认):IOC容器启动会调用方法创建对象放到IOC容器中
以后每交获取就是直接从容器(理解成从map.get对象)中拿
request: 主要针对WEB应用,同一次请求创建一个实例
session: 同一个session创建一个实例(后面两个用得不多,了解即可)

lazy懒加载

新建Cap4MainConfig.java:

@Configuration
public class Cap4MainConfig {
	//给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
	/*
	 * 懒加载: 主要针对单实例bean:默认在容器启动的时候创建对象
	 * 懒加载:容器启动时候不创建对象, 仅当第一次使用(获取)bean的时候才创建被初始化
	
	 */
	@Lazy
	@Bean
	public Person person(){
		System.out.println("给容器中添加person.......");
		return new Person("james",20);
	}
}
  • 加上@Lazy说明此bean是懒加载的, 只有获取anno.getBean时才会加载到IOC容器中.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值