Spring03

依赖检查 [已经撤销]

在Spring中可以使用依赖检查功能,以确保所要求的属性可设置或者注入dependency-check=“all”

4个依赖检查支持的模式:1、none没有依赖检查,这是默认的模式。2、simple如果基本类型和集合类型的任何属性都没有设置,抛出UnsatisfiedDependencyException。3、objects如果对象类型的任何属性都没有设置抛出UnsatisfiedDependencyException。4、all如果任何类型的任何属性都没有被设置则排除异常。
注:默认模式是none

全局默认的依赖检查 default-dependency-check=“all”

强调不要滥用依赖注入

1、ApplicationContext可以创建Java对象,但并不是所有的Java对象都通过依赖注入来创建的
2、Spring是一个很棒的框架,但是就易读性和易管理性而言,当定义大量bean的时候,基于XML的配置问题就会突出。过度依赖注入会使XML配置变得复杂而且臃肿
3、定义大量bean的时候,使用强大的IDE时,例如Eclipse,与XML文件相比,Java代码更加易读,易维护,易管理

Spring创建对象的五种方法

1、无参构造器,创建一个没有初始化数据的对象,默认就是无参构造器<property name="name" value="yan"/>
2、有参构造器,创建一个有初始化数据的对象<constructor-arg index="0" value="yanjun"/>
3、通过静态方法工厂创建对象<bean id="stu" class="com.yan.MyFactory" factory-method="newInstance"/>相当于调用静态方法工厂MyFactory.newInstance()
4、通过实例工厂创建对象[抽象工厂模式]
<bean id="fac" class="com.yan.MyFactory"/> 先创建工厂对象
<bean id="stu" factory-bean="fac" factory-method="newInstance" />再使用工厂对象调用方法实例化对象
5、通过实现FactoryBean接口,泛型T是当前此工厂需要返回的对应的Bean类型。Spring提供FactoryBean接口定制实例化bean的逻辑,一般用于实例化bean过程比较复杂时

public class MyFactory implements FactoryBean<Student>

<bean id="stu" class="com.yan.MyFactory"/>

日志的使用

添加依赖:slf4j-log4j12

添加日志配置文件log4j.properties

log4j.rootLogger=ALL, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

lookup方法注入

IoC容器具有复写bean方法的能力,CGLib可以在运行期动态操作Class字节码,为bean动态创建子类或者实现类

public interface MagicBoss {
	Car getCar();
}

不用编写任何实现类,仅仅通过配置为接口提供动态的实现,调用getCar可以每次都返回新的Car

<bean id="car" class="com.yan.Car" p:brand="大众" p:price="2000" scope="prototype" />

<bean id="magicBoss" class="com.yan.MagicBoss">
	<lookup-method name="getCar" bean="car" />
</bean>

方法替换

使用某个bean的方法去替换另一个bean的方法

public class Boss1{
	public Car getCar(){ ... ... }
}

Boss2实现了MethodReplacer接口,并在接口种返回一个新的Car对象

public class Boss2 implements MethodReplacer {
	public Object reimplement(Object arg0, Method arg1, Object[] arg2) throws Throwable{
		return 新的Car实现;
	}
}

对应配置

<bean id="boss1" class="com.yan.Boss1">
	<replaced-method name="getCar" replacer="boss2"/>使用boss2对象中的方法替换boss1中的方法
<bean id="boss2" class="com.yan.Boss2" />

不同配置方式比较

  • 基于xml配置:bean实现类来源于第三方类库,因此无法在类中标注注解,通过xml配置方式较好;如果想用命名空间的配置则只能使用基于xml的配置
  • 基于注解配置:bean的实现类是在当前项目开发的,可以直接在Java类中使用基于注解的配置
  • 基于JavaConfig配置:JavaConfig方式的优势在于可以通过代码方式控制bean初始化的整体逻辑,所以如果实例化bean的逻辑比较复杂时就比较适合使用JavaConfig类配置的方式

Bean生命周期方法

当一个bean被实例化时可能需要执行一些初始化使它转换成可用状态。同样当bean不再需要并且从容器中移除时,可能需要做一些清除工作。

  • 初始化回调<bean id="exampleBean" class="com.yan.ExampleBean" init-method="init"/>指定带有void无参数方法的名称 InitializingBean接口
  • 销毁回调<bean id="exampleBean" class="com.yan.ExampleBean" destroy-method="destroy"/>指定带有void无参数方法的名称 DisposableBean接口

建议不要使用InitializingBean或者DisposableBean的回调方法,因为XML配置在命名方法上提供了极大的灵活性。

@PostConstruct和@PreDestroy

@PostConstruct注解用于需要在依赖注入完成后执行以执行任何初始化的方法。只能用此注解一个方法。
类似于静态代码块和一般代码块的作用,会在加载时自动执行一次被修饰的方法,且该方法只能是没有返回值的void非静态方法。

在spring中bean的初始化过程中,方法执行先后顺序为Constructor > @Autowired > @PostConstruct。先执行完构造方法,再注入依赖,最后执行初始化操作,所以这个注解就避免了一些需要在构造方法里使用依赖组件的尴尬,可以将依赖注入的对象设置到其它属性种进行初始化操作。

@Service 
public class BeanA { 
	@Autowired 
	private BeanB beanB; 

public BeanA() { 
	System.out.println("这是Bean A 的构造方法"); } 

@PostConstruct 
private void init() { 
	System.out.println("这是BeanA的 init 方法"); 
	beanB.testB(); } 
}

BeanFactory和Application

Spring设计了BeanFactory和ApplicationContext两个接口用以表示容器。

BeanFactory使用比较简单,可以理解为就是HashMap,Key是BeanName,Value是Bean实例。通常只提供注册put,获取get这两个功能。可以称之为低级容器。
ApplicationContext可以称之为高级容器。是BeanFactory的子接口,比BeanFactory多更多的JavaEE企业级功能。例如资源的获取,支持多种消息等。应用上下文代表着整个大容器的所有功能。该接口定义了一个refresh方法,此方法用于刷新整个容器,即重新加载/刷新所有的bean。

ApplicationContext接口有两个常用的实现类:

1、ClassPathXmlApplicationContext加载类路径ClassPath下指定的XML配置文件并完成ApplicationContext的实例化工作。ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);

2、FileSystemXmlApplicationContext加载指定的文件系统路径中指定的XML配置文件并完成ApplicationContext的实例化工作。ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);

IoC在Spring里只需要低级容器就可以实现。2个步骤:

1、加载配置文件,解析成BeanDefinition放在Map里。

2、调用getBean时从BeanDefinition所属的Map里,拿出Class对象进行实例化,同时,如果有依赖关系,将递归调用getBean方法。完成依赖注入。

IoC底层通过工厂模式、Java的反射机制、XML解析等技术,将代码的耦合度降低到最低限度,其主要步骤:

1、在配置文件Bean.xml中,对各个对象以及它们之间的依赖关系进行配置;

2、可以把IoC容器当做一个工厂,这个工厂的产品就是Spring Bean;

3、容器启动时会加载并解析这些配置文件,得到对象的基本信息以及它们之间的依赖关系;

4、IoC利用Java的反射机制,根据类名生成相应的对象Spring Bean,并根据依赖关系将这个对象注入到依赖它的对象中。

IoC容器启动过程

1、加锁,防止在refresh的时候出现启动或销毁容器的操作。synchronized (this.startupShutdownMonitor)

2、准备工作,记录下容器的启动时间、标记已启动状态、处理配置文件中的占位符。prepareRefresh();

3、初始化BeanFactory,先创建DefaultListableBeanFactory实例,然后将配置信息解析成beanDefinition,并封装成beanName -> beanDefinition的ConcurrentHashMap放在BeanFactory。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

4、BeanFactory后置器处理。prepareBeanFactory(beanFactory);

5、加载、注册Bean,添加一些特殊的BeanFactoryPostProcessor的实现类或做点什么事。
postProcessBeanFactory(beanFactory);

6、BeanPostProcessor的实现并注册。invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);

7、对上下文的消息源进行初始化并处理。initMessageSource();

8、钩子方法初始化特殊Bean。onRefresh();

9、注册事件监听器,检查监听Bean并且将这些Bean向容器注册。 registerListeners();

10、初始化所有单例Bean,根据Bean的不同类型通过AbstractBeanFactory的getBean()获取,然后createBean()。创建bean实例(参数封装)finishBeanFactoryInitialization(beanFactory);

11、发布广播事件,结束refresh过程。finishRefresh();

Spring bean生命周期

1、Spring启动查找并加载需要被Spring管理的Bean,进行Bean的实例化;

2、Bean实例化后,对Bean的引入和值注入到Bean的属性中;

3、如果Bean实现BeanNameAware接口,Spring将Bean的Id传递给setBeanName()方法;

4、如果Bean实现BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;

5、如果Bean实现ApplicationContextAware接口,Spring将调用Bean的setApplicationContext()方法将Bean所在应用上下文引用传入进来;

6、如果Bean实现BeanPostProcessor接口,Spring就将调用postProcessBeforeInitialization()方法;

7、如果Bean实现InitializingBean接口,Spring将调用afterPropertiesSet()方法。类似如果Bean使用init-method声明了初始化方法,该方法也会被调用;

8、如果Bean实现BeanPostProcessor接口,Spring就将调用postProcessAfterInitialization()方法;
此时Bean已经准备就绪,可以被应用程序使用了。它们将一直驻留在应用上下文中,直到应用上下文被销毁;

9、如果Bean实现DisposableBean接口,Spring将调用destory()接口方法,同样如果Bean使用了destory-method声明销毁方法,该方法也会被调用。

循环依赖问题

循环依赖会产生级联效应, 这个环中的某一点产生不稳定变化,都会导致整个环产生不稳定变化;而且可能会导致内存溢出问题。循环依赖只有单例的setter注入能解决;多例的setter注入和构造器注入都不能解决

DefaultSingletonBeanRegistry 维护了三个 Map 用于缓存不同状态的 Bean。

  • 一级缓存 singletonObjects缓存的是已经经历了完整生命周期的bean对象
  • 二级缓存earlySingletonObjects缓存的是早期的bean对象,早期指的是Bean的生命周期还没走完
  • 三级缓存singletonFactories缓存的是 ObjectFactory对象工厂,用来创建某个对象的代理对象。

受管bean的生成步骤

1、Spring扫描class得到BeanDefinition;

2、根据得到的BeanDefinition去生成bean;首先根据class推断构造方法;根据推断出来的构造方法,反射,得到一个对象,暂时叫做原始对象;

3、填充原始对象中的属性,就是依赖注入;

4、如果原始对象中的某个方法被AOP了,那么则需要根据原始对象生成一个代理对象;

5、把最终生成的代理对象放入单例池即singletonObjects中,下次getBean时就直接从单例池拿即可;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值