Spring加载过程

310 阅读5分钟

1、Spring提供了2种不同的容器类型:Bean工厂和上下文,其中上下文是基于Bean创建的。 目前容器基本以上下文为主。 原因:主要在于单例bean如何被加载。 Bean工厂:延迟加载所有bean,直到getBean()方法被调用的时候才会创建bean的实例对象,效率较低。 上下文:在启动后预载入所有单例bean,需要的时候直接getBean()取出即可,这样可以确保应用不需要等待他们被创建。 举个通俗的例子,某个人在天气很冷的时候外出,回来的时候想喝热水,Bean工厂需要现场泡热水,而上下文在这个人外出的时候已经泡好热水了,这个人想喝的时候就可以直接喝热水,无需等待。 2、上下文常见的有几种:AnnotationConfigApplicationContext、AnnotationConfigWebApplicationContext、ClassPathXmlApplicationContext、FilSystemApplicationContext、XmlWebApplicationContext。运用上下文准备就绪之后就可以调用上下文的getBean()从Spring容器获取到bean。

控制反转(IOC)或者就叫做依赖注入(DI):对于运用对象之间的解耦。 创建运用对象之间协作关系的行文通常称为装配,这也是依赖注入的本质。 自动化装配Bean的方案: 1、组件扫描:Spring会自动发现运用上下文中所创建的Bean。常见的注解:@Component、@ComponentScan 2、自动装配:Spring自动满足Bean之间的依赖,注解包括@Authowired、@Inject,(这2个注解的意思大部分上是一样的。) 显示配置Bean的方案:创建一个Configuration类,并添加上@Configuration注解,然后在方法上添加@Bean注解,会告诉Spring这个方法将返回一个对象。

假设我们需要只有某个Bean只有当另外个Bean声明了才创建,也就是说对于某个Bean的生成是有条件的,那么我们可以使用@Conditional这个注解。

自动装配的歧义性 在上诉已经说了自动装配的方案:@Authoried,假设我们引入了@Authoried UserService这个类,并且在实现类实现该接口,注入@Compent,其中有多个实现类实现了该接口,那么Spring就会产生歧义,不知道怎么选择,抛出NoUniqueBeanDefinitionException异常,Spring为我们提供了解决方法,采用@Primary、@Qualifier注解。 其中@Primary表示首选项,比如A、B、C3个实现类,在A实现类加上@Primary注解就表示Spring会加载A这个实现类,但是的话如果在B、C再加上这个注解的话Spring就会报错,也就是说@Primary只能使用一次。

Bean的作用域: 默认情况下,Spring的Bean都以单例(Singleton)的形式创建的,也就是说,不管给定的一个Bean被注入到其他Bean多少次,每次注入的都是同一个实例。 其他的作用域还包括: 原型(Prototype):每次注入或者通过上下文获取的时候,都会创建一个新的Bean实例。 会话(Session):为每一个会话创建一个Bean实例。 请求(Request):为每一个请求创建一个Bean实例。 全局会话(Global Session) 如果需要改变成Prototype作用域的的话,可以添加注解@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE);而如果要换成会话、请求、全局会话这些作用域的话,添加注解@Scope(value=WebApplicationContext.对应的作用域名称,proxyMode=ScopedProxyMode.INTERFACES/TARGET_CLASS) 其中ScopedProxyMode.INTERFACES表示Spring会创建基于接口的代理,而如果是类的话,ScopedProxyMode.TARGET_CLASS则使用这个,表示Spring通过CGlib生成类的代理。

面向切面(AOP):实现横切关注点与它们所影响的对象之间的解耦。 切面:对于一些通用的功能,可以通过声明的方式定义要以何种方式在何处使用,即使修改也不会受影响的类。 通知:即切面的目标,定义了什么时候使用,包括5种通知、Before、After、After-returing、After-throwing、Around 连接点:运用执行过程中能够插入切面的一个点。 切点:匹配通知所要织入的一个或者多个连接点,通常使用明确的类和方法名称来指定这些切点。 切面:是通知和切点的结合,通知定义了切面是什么,在何时调用,切点定义了在何处工作。 织入:将切面应用到目标对象来创建的代理对象过程。

aspectJ表达式:切点表达式 如execution(** cn.itcast.service..(..)) 其中 第一个表示任意的修饰符,如public、private;第二个表示返回类型任意;..表示任意参数。 此外,还有诸如arg、within等等进行限制的等待,不再一一赘述。 要想定义一个切面的话,需要在某个类上添加@Aspect表示这是一个切面,然后的话通过以上的表达式和5个通知进行整合。如@Before("execution(cn.itcast.service..(..))")即表示在方法开始前调用。 如果多个通知都使用了同个切点表达式的话,那么我们可以使用@Pointcut来表达。 如@Pointcut("execution( cn.itcast.service..(..))") public void performance() {} 这里的performance可以自定义,无实际意义。
@Before("performance()") @After("performance()") 此外,如果是使用JavaConfig的话,也就是有@Bean注解的话,需要在这个类上添加@EnableAspectJAutoProxy注解来表示开启自动代理功能。