您的位置:首页 > 编程语言 > Java开发

Spring Framework笔记(二)

2016-07-13 06:43 525 查看

IoC容器

IoC也就是DI,其实是规定了当前对象A所依赖的对象B必须要通过以下方式传入A:

A构造函数的参数

指向A的工厂方法参数

A的属性文件

上述过程之所以叫做反转控制,是因为A可以控制它的依赖对象B的实例化。在spring-bean和spring-context里面有BeanFactory和它的子接口ApplicationContext来实现反转控制。

一个重要的概念叫做bean,bean指的是被Spring IoC容器管理的开发者应用中的核心部分。如果bean没有被IoC容器控制,那么它就是一个简单的对象。

容器简介

ApplicationContext就代表了Spring的IoC容器。它负责根据configuration metadata实例化,配置,组装一系列bean。

Configuration metadata其实就是XML文件/Java注解/Java代码用来告诉IoC容器你所制定的规则。简单的讲,

System=Container(Metadata+POJOs)

为了告诉容器一个类是一个bean,我们可以在XML里面定义标签bean或者在java里面@Configuration注解的类里面用@Bean注解相应的类方法。通常需要定义的bean包括service layer object,data access object,presentation object, infrastructure object等等。

实例化容器可以通过ClassPathXmlApplicationContext来导入相应的XML文件。如果需要在程序中读取bean的实例,可以通过context.getBean()得到。但是,如果你需要getBean,那你的应用就会对Spring API产生依赖,我们不希望这种依赖发生。

Bean简介

bean的定义存在于BeanDefinition对象里面,包含了实现bean的类名,bean的动作类配置(scope, lifecyle callbacks, etc.),所依赖的类,其它配置。

Spring支持通过ApplicationContext的getBeanFactory()来得到DefaultListableBeanFactory(),然后可以registerSingleton()和registerBeanDefinition()来加入外部bean。对于metadata和singleton的实例,它们应该被尽早的注册以使得autowire可以使用。runtime注册bean是不支持的。

依赖

依赖可以有两种方式注入,通过constructor和setter两种方式:

constructor注入类似于直接在bean的构造函数里面指明如何去做。比较适合mandatory dependencies。推荐使用,因为不会产生dependencies是null的情况。

setter注入类似通过工厂类方法告诉bean需要创建这么一个对象。一般用于optional dependencies。可以通过加@Required注解变成required dependency。

dependency解析过程如下(类比Java object的new过程):

容器load: ApplicationContext被初始化(configuration metadata)

创建bean: 对每一个bean,它们的dependencies会在bean创建的时候提供,创建bean的property或者constructor argument会被加入

在XML配置文件中,可以用p-namespace来替代property标签:

<bean name="classic" class="com.example.Person">
<property name="name" value="John"/>
<property name="spouse" ref="Jane"/>
</bean>

<bean name="p-namespace" class="com.example.Person"
p:name="John"
p:spouse-ref="Jane"/>


同样的,constructor-arg也可以用c-namespace来替代。

注入方法通常发生在一个singleton bean需要调用非singleton bean的时候。为了处理这种问题,可以让singleton bean利用ApplicationContextAware接口来通知容器去实例化非singleton bean。

Bean作用范围

singleton (默认):容器仅仅创建一个实例,并将其放在用来存放singleton bean的cache里面。(适用于无状态bean)

prototype:一个bean class对应多个实例,需要的时候由容器实例化。(适用于有状态bean)Spring负责prototype bean的实例化,配置,组装,交给客户。因此,清理bean的实例将由客户完成,或者,需要bean的post-processor来清理。这点类似于Java的new,但是没有delete。

request, session, globalSession, application, websocket:这些都是web应用的scope。如果使用Spring MVC,那么DispatcherServlet将会自动处理bean的范围。如果request不在DispatcherServlet范围内,那么可以考虑RequestContextListener和RequestContextFilter。

对于这些范围型bean,如果short-lived bean要被注入到long-lived bean,那么我们需要利用aop:scoped-proxy来完成。简单的讲,如果一个session-scope bean要被注入到singleton bean或者application-scope bean,在不使用proxy的情况下,session-scope bean其实一直是singleton bean初始化时候的被初始化的bean。加入了proxy就意味着proxy会去获取session-scope bean对应于当前session的实例。

bean的生命周期管理

当一个bean在生命周期开始和结束的时候,我们可以选择加入做一些自定义的code。这个可以通过容器的@PostConstruct / init-method和@PreDestroy / destroy-method方法来实现。有时候,你不得不使用SmartLifecycle来自定义bean的shutdown方法(在非web的情况下,开发者需要保证这点)。

Bean定义的继承

bean是可以被继承的,只需要在子bean里面加入父bean作为parent属性即可,另外,也可以声明父bean为abstract。这点类似于标准的Java。

容器扩展点

在Spring中,可以利用BeanPostProcessor来操纵bean的实例(注意,这个processor是在实例化以后起作用的)。AOP在bean里面正是通过这种方式来放置切入点的。

另外一种扩展点是利用BeanFactoryPostProcessor。和前面的processor不同的是,这里的processor可以在任何bean实例化之前读取并且更改configuration metadata。但是,如果需要更改一个已经实例化的bean,那么还是要用BeanPostProcessor。

对于FactoryBean接口,它可以用来实现容器初始化的复杂逻辑。如果需要得到FactoryBean的实例,那么,可以利用
ApplicationContext.getBean()
。但是需要注意的是,参数需要加上&符号(比如,”¤tBean”),否则,得到的是currentBean的实例)。

注解配置

关于注解配置和XML配置哪种好的争论,我们暂且不谈,因为不同的开发者有不同的偏好。需要注意的是,如果在你的配置里面两者都有,那么XML注入会覆盖注解注入。

@Required:对于bean的setter方法,这个注解表明了setter对应的属性必须在配置的时候读取,避免了NullPointerException。

@Autowired:可以在很多时候使用来做为依赖注入的主要方法。@Autowired,@Inject,@Resource,@Value注解是由Spring的BeanPostProcessor来实现的,所以,BeanPostProcessor和BeanFactoryProcess不能被注解。对于多重bean定义,可以利用@Primary,或者更为广泛的@Qualifier注解来定义。这样,在@Autowired注解里面,就可以选择使用。

@Resource:和@Autowired不同,@Resource可以利用bean的名字来注解,@Autowired则是利用bean的类型来注解。

@PostConstruct和@PreDestroy提供了bean生命周期的注解。

classpath扫描和管理组件

@Component用来表示一个通用的由Spring管理的组件。如果想要具体的应用, 可以利用@Repository一般标明一个组件是一个DAO,用在持久层;利用@Service来表明一个服务;利用@Controller来表明表示层。

注解还可以和另外一个注解一起使用成更具体的注解。例如,@RestController = @Controller + @ResponseBody。

为了能自动检测并且注册这些组件,我们需要利用@Configuration和@ComponentScan。

JSR 330注解

@Autowired可以由@Inject来替代,@Component可以由@Named来取代。但是,功能性的比较上还是利用Spring自己的注解比较好。

基于Java的容器配置

@Bean的作用就是告诉容器bean的存在,@Configuration则是用于替代传统的XML文件。为了不产生多次调用一个bean的情况,Spring建议将bean的定义放在@Configuration类里面。示例:

public static void main(String[] args) {
AnnotationConfigApplicationContext ctx
= new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.register(OtherConfig.class);
ctx.refresh();
MyService mySvc = ctx.getBean(MyService.class);
mySvc.doStuff();
}
====================================================
@Configuration
@ComponentScan(basePackage = "com.example")
public class AppConfig {
@Bean(initMethod = "init", destroyMethod = "cleanup")
@Scope("prototype")
public MyService myService() {
...
return new MyServiceImpl();
}
}
====================================================
public class MyServiceImpl {
public void init() {
...
}
public void cleanup() {
...
}
}


@Import可以用来导入其它的配置文件类。@Conditional用来注解
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring framework