Spring源码深度解析,Spring源码以及组件,@ComponentScan   扫描组件,@Scope Bean 的生命周期管理,@Lazy 懒加载(三)(附代码示例:)

三)初始Spring源码以及常用组件

目录

三)初始Spring源码以及常用组件

一,@ComponentScan   扫描

示例源码3.1.1:一般我们在扫描的都是使用 xml 方式 去扫描 整个项目,

示例源码3.1.1:使用@ComponentScan 注解  定义范围扫描

示例源码3.1.2:一般我们在扫描的都是使用 xml 方式 去自动扫描,

示例源码3.1.3:一般我们在扫描的都是使用 xml 方式 去自定义规则扫描, 

二,@Scope :Bean 的生命周期管理

3.2.1 ,@Scope("prototype")示例:   结果最后 执行的 内存地址不一样,返回==>false

3.2.2,@Scope("singleton")示例:   结果最后 执行的 内存地址不一样,返回  ====>true,  

3.2.3 ,@Scope("prototype")  XML示例结果最后 执行的 内存地址不一样,返回 ==>false,  

三,@Lazy   即:懒加载,延时加载 主要针对单例bean:默认在容器启动的时候不创建对象,仅当第一次使用(获取)bean的时候才创建被初始

3.3.1 示例源码:默认在容器启动的时候不创建对象

四,项目 Demo


 一,@ComponentScan   扫描

  • 指定扫描范围
  • 扫描过滤器
  • 自定义扫描规则

示例源码3.1.1:一般我们在扫描的都是使用 xml 方式 去扫描 整个项目,

//base-pacjage 是指扫描范围
<context:component-scan base-package="org.java"></context:component-scan>

示例源码3.1.1:使用@ComponentScan 注解  定义范围扫描

@Configuration
@ComponentScan(value="com.enjoy.cap2")


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

}


@Repository
public class OrderDao {

}

@Service
public class OrderService {

}
public class Cap2Test {
	@Test
	public void test01(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
		
		//通过注解拿到bean 的id
		String[] names = app.getBeanDefinitionNames();
		
		for(String name:names){
			System.out.println(name);
		}
	}
}

为了测试,我在同一个项目下面 分别写了  @Controller @Repository @Service  ,结果意料中的全部被扫描到

 

示例源码3.1.2:一般我们在扫描的都是使用 xml 方式 去自动扫描,


//  includeFilters Filter 后面的意思是只扫描出 Controller
 // useDefaultFilters:设置为false 可以扫描全部
@Configuration
@ComponentScan(value="com.enjoy.cap2", includeFilters={
		@Filter(type=FilterType.ANNOTATION, classes={Controller.class})
}, useDefaultFilters=false)


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

然而没什么用,我们在 xml 可以直接指定

//base-pacjage 是指扫描范围,自定义
<context:component-scan base-package="org.java,Controller"></context:component-scan>

示例源码3.1.3:一般我们在扫描的都是使用 xml 方式 去自定义规则扫描, 

@Configuration
@ComponentScan(value="com.enjoy.cap2", includeFilters={
		@Filter(type=FilterType.CUSTOM, classes={JamesTypeFilter.class})
}, useDefaultFilters=false)

//@Filter: 扫描规则
//@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,使用自定义扫描范围
//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] 指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件
//useDefaultFilters = false 默认是true,扫描所有组件,要改成false
//----扫描规则如下
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按BookService类型
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口
public class Cap2MainConfig {
	//给容器中注册一个bean, 类型为返回值的类型, 
	@Bean
	public Person person01(){
		return new Person("james",20);
	}
}

新增自定义过滤规则类: 如果 类名包含有“Order”  返回 ==》true

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")){//当类包含er字符, 则匹配成功,返回true
			return true;
		}
		return false;
	}

}
public class Cap2Test {
	@Test
	public void test01(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
		
		
		String[] names = app.getBeanDefinitionNames();
		
		for(String name:names){
			System.out.println(name);
		}
	}
}

 扫描,三个类, 三个类名都包含有 Order   

 

 

二,@Scope :Bean 的生命周期管理

  简单来说: 对象在spring容器(IOC容器中的生命周期,也可以理解为对象在spring容器中的创建方式。

  •  prototype  即多实例:IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象,而是每次获取的时候才会调用方法创建对象
  • singleton  即单例模式:IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿的同一bean
  • request    即主要针对web应用,递交一次请求创建一个实例。Spring 容器 即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,该对象的生命周期即告结束,如同java web中request的生命周期。当同时有10个HTTP请求进来的时候,容器会分别针对这10个请求创建10个全新的RequestPrecessor实例,且他们相互之间互不干扰,简单来讲,request可以看做prototype的一种特例,除了场景更加具体之外,语意上差不多。
<bean id ="requestPrecessor" class="...RequestPrecessor"   scope="request" />
  •   session  同一个session创建一个实例,Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,比request scopebean会存活更长的时间,其他的方面没区别。对于web应用来说,放到session中最普遍的就是用户的登录信息,对于这种放到session中的信息,我们可以使用如下形式的制定scope为session:
    <bean id ="userPreferences" class="...UserPreferences"   scope="session" />

    3.2.1 ,@Scope("prototype")示例:   结果最后 执行的 内存地址不一样,返回==>false

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

 

@Test
	public void test01(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
		
		
		String[] names = app.getBeanDefinitionNames();
		
		for(String name:names){
			System.out.println(name);
		}
		//从容器中分别取两次person实例, 看是否为同一个bean
		Object bean1 = app.getBean("person");
		Object bean2 = app.getBean("person");
		System.out.println(bean1 == bean2);
		//结论:bean1就是bean2,同一个对象
		
	}

  

3.2.2,@Scope("singleton")示例:   结果最后 执行的 内存地址不一样,返回  ====>true,  

@Configuration
public class Cap3MainConfig {
	
	/*
	 * 这里也可以直接不使用 注解@Scope ,给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
	 * singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿(大Map.get)的同一个bean
	 */
	//@Scope("singleton")
    @Scope("singleton")
	@Bean
	public Person person(){
		return new Person("james",20);
	}
}
@Test
	public void test01(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
		
		
		String[] names = app.getBeanDefinitionNames();
		
		for(String name:names){
			System.out.println(name);
		}
		//从容器中分别取两次person实例, 看是否为同一个bean
		Object bean1 = app.getBean("person");
		Object bean2 = app.getBean("person");
		System.out.println(bean1 == bean2);
		//结论:bean1就是bean2,同一个对象
		
	}

 

3.2.3 ,@Scope("prototype")  XML示例结果最后 执行的 内存地址不一样,返回 ==>false,  

   将 scope 属性改成 singleton  就是单例

<bean id="prototypeCap3" class="com.enjoy.cap3.config.Cap3MainConfig" scope="prototype"></bean>


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

public class Cap3Test {
	@Test
	public void test01(){
		//AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
		//把beans.xml的类加载到容器
		ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
		
		String[] names = app.getBeanDefinitionNames();
		
		for(String name:names){
			System.out.println(name);
		}
		//从容器中分别取两次person实例, 看是否为同一个bean
		Object bean1 = app.getBean("person");
		Object bean2 = app.getBean("person");
		System.out.println(bean1 == bean2);
		//结论:bean1就是bean2,同一个对象
		
	}
}

三,@Lazy   即:懒加载,延时加载 主要针对单例bean:默认在容器启动的时候不创建对象,仅当第一次使用(获取)bean的时候才创建被初始

3.3.1 示例源码:默认在容器启动的时候不创建对象

public class Cap4MainConfig {
	//给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
	/*
	 * 懒加载: 主要针对单实例bean:默认在容器启动的时候创建对象
	 * 懒加载:容器启动时候不创建对象, 仅当第一次使用(获取)bean的时候才创建被初始化
	
	 */
	@Lazy
	@Bean
	public Person person(){
		System.out.println("给容器中添加person.......");
		return new Person("james",20);
	}
}
public class Cap4Test {
	@Test
	public void test01(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap4MainConfig.class);
		
		System.out.println("IOC容器创建完成........");
		app.getBean("person");//执行获取的时候才创建并初始化bean
		
	}
}

 执行结果: 在容器创建之后, 并没有去创建bean  ,而是在获取bean的时候才去创建并初始化

 

四,项目 Demo

Spring源码深度解析,(附代码示例 码云地址: https://gitee.com/Crazycw/SpringCode.git

参考资料:  https://docs.spring.io/spring/docs/4.3.18.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/

请看下篇:Spring源码深度解析,Spring源码以及组件(四)(附代码示例:)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可乐cc呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值