Spring学习笔记6

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/attack_breast/article/details/74933458

Spring简述

1. 简化Java开发

为了降低Java开发的复杂性,Spring采取了以下4种关键策略:

①基于POJO的轻量级和最小侵入性编程;

②通过依赖注入和面向接口实现松耦合;

③基于切面和惯例进行声明式编程;

④通过切面和模板减少样板式代码。

2. 应用切面

DI能够让相互协作的软件组件保持松散耦合,而面向切面编程(aspect-oriented programmingAOP)允许你把遍布应用各处的功能分离出来形成可重用的组件。

面向切面编程往往被定义为促使软件系统实现关注点的分离一项技术。系统由许多不同的组件组成,每一个组件各负责一块特定功能。除了实现自身核心的功能之外,这些组件还经常承担着额外的职责。诸如日志、事务管理和安全这样的系统服务经常融入到自身具有核心业务逻辑的组件中去,这些系统服务通常被称为横切关注点,因为它们会跨越系统的多个组件。

AOP能够使这些服务模块化,并以声明的方式将它们应用到它们需要影响的组件中去。所造成的结果就是这些组件会具有更高的内聚性并且会更加关注自身的业务,完全不需要了解涉及系统服务所带来复杂性。总之,AOP能够确保POJO的简单性。

3. Bean容器

BeanFactory:最简单的容器,提供基本的依赖注入支持。

ApplicationContext:基于BeanFactory构建并提供应用框架级别的服务。

AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。

AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文。

ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。

FileSystemXmlapplicationcontext:从文件系统下的一个或多个XML配置文件中加载上下文定义。

XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义。

ApplicationContext  ctx = new FileSystemXmlApplicationContext(“c:/learn.xml”);

ApplicationContext  ctx = new ClassPathXmlApplicationContext(“learn.xml”);

ApplicationContext  ctx = new AnnotationConfigApplicationContext(Learn.class);

4. Bean生命周期

实例化------》填充属性-----》调用BeanNameAwaresetBeanName方法-----》调用BeanFactoryAwaresetBeanFactory方法---------》调用ApplicationContextAwaresetApplicationContext方法---------》调用BeanPostProcessorpostprocessBeforeInitialization方法--------》调用InitializingBeanafterPropertiesSet方法------------》调用自定义的初始化方法--------------》调用BeanPostProcessorpostProcessAfterInitialization方法----------》使用Bean------------》容器关闭----------》调用DisposableBeandestroy方法---------》调用自定义的销毁方法

Bean管理

配置Bean方式:

1、在XML中进行显式配置。

2、在Java中进行显式配置。

3、隐式的Bean发现机制和自动装配。

1. 隐式的Bean发现机制和自动装配

Spring从两个角度来实现自动化装配:组件扫描(Spring会自动发现应用上下文中所创建的Bean)、自动装配(Spring自动满足Bean之间的依赖)

组件扫描常用注解:

@Component注解:类注解,标注一个JAVA类是组件,可以通过该注解为组件起一个独一无二的ID,默认Spring会将类名的第一个字母变为小写作为其ID

@ComponentScan注解:类注解,启用系统的组件扫描功能,默认扫描与配置类相同的包,可以通过value/basePackages属性来配置扫描路径,value只能配置一个路径而basePackages可以配置多个;String类型的路径绑定了代码,可以通过basePackageClasses来指定扫描的接口/类,这些类所在的包将会作为组件扫描的基础包。

@Configuration注解:类注解,负责标记该JAVA类是配置类,该配置类中的方法主要功能是负责返回我已经写好的Bean,你可以把配置类理解成工厂类。

@ContextConfiguration注解:类注解,参数是class对象,负责加载配置类。

@Autowired注解:属性注解,该属性自动注入。

在你的应用程序中,如果所有的对象都是独立的,彼此之间没有任何依赖,那所需的可能就是组件扫描而已,方便获取实例对象;但是,如果很多对象会依赖其他对象才能完成任务,这样的话,就需要自动装配。

自动装配常用注解:

@Autowired注解:可以用在任何方法/属性上,Spring都会尝试满足方法参数上所声明的依赖,假如有且只有一个Bean匹配的话那么这个Bean将会被装配进来,如果没有匹配的Bean,那么应用上下文创建的时候Spring会抛出一个异常,为了避免这个异常可以将该注解的required属性设置为false,这样的话你需要对参数添加非空判断。

2. Java中进行显式配置

将第三方库中的组件装配到应用中时自动装配就不好用了,改用显式配置。常用注解如下:

@Configuration注解:类注解,标记JAVA类是配置类

@Bean注解:方法注解,标记该方法所返回的对象要被Spring注册为一个Bean,默认该BeanID是被该注解修饰的方法名,如果想修改ID的话,可以通过name属性来指定,这里Spring默认Bean全部是单例的,一旦某方法添加了该@Bean注解,那么,系统中凡是对该方法的调用都会被Spring拦截来确保该方法所返回的JAVA对象是Spring中的、同一个JAVA对象。

@Autowired注解:属性注解,该属性自动注入。

3. XML中进行显式配置

1<bean  id=""  class=""/>

2、在通过构造器来传入其他JAVA对象时,通常有2种基本的配置方法

<constructor-arg>元素、使用Spring3.0所引入的c-命名空间

3<constructor-arg  ref=""/>/<bean  id=""  class=""  c:cd-ref=""/>

4c命名空间组成:c-命名空间前缀:参数名称/_参数索引 引用(-ref表示引用)=“要注入的BeanID”,当只有一个参数时c-命名空间可以这样写:c:_-ref="";如果设置为字面量的话,则可以是这样:c_title=”test”

5<constructor-arg  value=””><null/><list/><set/></constructor-arg>,其中<value/>代表字面量,<ref>代表引用

6、在装配集合方面,<constructor-arg>c-命名空间的属性更有优势。目前,使用c-命名空间的属性无法实现装配集合的功能。

7、属性注入:<property  name=”  ref/value=”””/>,该XML元素为了简化,对应有p-命名空间,P-命名组成为:p:属性名 –ref/value=”XXX”

8util-命名空间,由于c-命名空间和p-命名空间无法使用集合,使用util-命名空间之后,c/p-命名空间就可以使用集合了

9、通过@Import注解来拆分@Configuration配置类

通过<import/>元素来拆分基于XML配置的XML

10XML配置、JAVA配置都是彼此可以互相调用的,其中JAVA配置通过@ImportResource(classpath:xxx.xml)注解来引用XML中配置好的BeanXML配置通过<bean/>来引用基于JAVA配置的配置类

高级装配

1. Spring3.1-profile-装配Bean

你首先要将所有不同的bean定义整理到一个或多个profile之中,在将应用部署到每个环境时,要确保对应的profile处于激活(active)的状态。在Java配置中,可以使用@Profile注解指定某个bean属于哪一个profile。没有指定profilebean始终都会被创建,与激活哪个profile没有关系。

@Profile注解应用在了类级别上。它会告诉Spring这个配置类中的bean只有在dev profile激活时才会创建。如果dev profile没有激活的话,那么带有@Bean注解的方法都会被忽略掉。

Spring 3.1中,只能在类级别上使用@Profile注解。不过,从Spring 3.2开始,你也可以在方法级别上使用@Profile注解,与@Bean注解一同使用。这样的话,就能将这两个bean的声明放到同一个配置类之中。

我们也可以通过<beans>元素的profile属性,在XML中配置profile bean。你还可以在根<beans>元素中嵌套定义<beans>元素,而不是为每个环境都创建一个profile  XML文件。这能够将所有的profile bean定义放到同一个XML文件中,示例如下图所示:

 

除了所有的bean定义到了同一个XML文件之中,这种配置方式与定义在单独的XML文件中的实际效果是一样的。这里有三个bean,类型都是javax.sql.DataSource,并且ID都是dataSource。但是在运行时,只会创建一个bean,这取决于处于激活状态的是哪个profile

2. 激活profile

Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属性:spring.profiles.activespring.profiles.default。如果设置了spring.profiles.active属性的话,那么它的值就会用来确定哪个profile是激活的。但如果没有设置spring.profiles.active属性的话,那Spring将会查找spring.profiles.default的值。如果spring.profiles.activespring.profiles.default均没有设置的话,那就没有激活的profile,因此只会创建那些

没有定义在profile中的bean

有多种方式来设置这两个属性:作为DispatcherServlet的初始化参数/作为Web应用的上下文参数/作为JNDI条目/作为环境变量/作为JVM的系统属性/在集成测试类上,使用@ActiveProfiles注解设置

spring.profiles.activespring.profiles.default中,profile使用的都是复数形式。这意味着你可以同时激活多个profile,这可以通过列出多个profile名称,并以逗号分隔来实现。

Spring提供了@ActiveProfiles注解,我们可以使用它来指定运行测试时要激活哪个profile

3. Spring4-@Conditional-装配Bean

Spring 4引入了一个新的@Conditional注解,它可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean会被忽略。@Conditional将会通过Condition接口进行条件对比,设置给@Conditional的类可以是任意实现了Condition接口的类型。可以看出来,这个接口实现起来很简单直接,只需提供matches()方法的实现即可。如果matches()方法返回true,那么就会创建带有@Conditional注解的bean。如果matches()方法返回false,将不会创建这些bean

实现Condition接口只需实现一个方法public Boolean matches(ConditionContext  context,  AnnotatedTypeMetadata  metadata);

通过ConditionContext,我们可以做到如下几点:

①借助getRegistry()返回的BeanDefinitionRegistry检查bean定义;

②借助getBeanFactory()返回的ConfigurableListableBeanFactory检查bean是否存在,甚至探查bean的属性;

③借助getEnvironment()返回的Environment检查环境变量是否存在以及它的值是什么;

④读取并探查getResourceLoader()返回的ResourceLoader所加载的资源;

⑤借助getClassLoader()返回的ClassLoader加载并检查类是否存在。

AnnotatedTypeMetadata则能够让我们检查带有@Bean注解的方法上还有什么其他的注解。像ConditionContext一样,AnnotatedTypeMetadata也是一个接口

 

借助isAnnotated()方法,我们能够判断带有@Bean注解的方法是不是还有其他特定的注解。借助其他的那些方法,我们能够检查@Bean注解的方法上其他注解的属性。非常有意思的是,从Spring 4开始,@Profile注解进行了重构,使其基于@ConditionalCondition实现。作为如何使用@ConditionalCondition的例子,我们来看一下在Spring 4中,@Profile是如何实现的。

 

我们可以看到,ProfileCondition通过AnnotatedTypeMetadata得到了用于@Profile注解的所有属性。借助该信息,它会明确地检查value属性,该属性包含了beanprofile名称。然后,它根据通过ConditionContext得到的Environment来检查[借助acceptsProfiles()方法]该profile是否处于激活状态。

4. 自动装配

仅有一个bean匹配所需的结果时,自动装配才是有效的。如果不仅有一个bean能够匹配结果的话,这种歧义性会阻碍Spring自动装配属性、构造器参数或方法参数。当确实发生歧义性的时候,Spring提供了多种可选方案来解决这样的问题。你可以将可选bean中的某一个设为首选(primary)的bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean

在声明bean的时候,通过将其中一个可选的bean设置为首选(primarybean能够避免自动装配时的歧义性。当遇到歧义性的时候,Spring将会使用首选的bean,而不是其他可选的bean。实际上,你所声明就是“最喜欢”的bean。在Spring中,可以通过@Primary来表达最喜欢的方案。@Primary能够与@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。<bean>元素有一个primary属性用来指定首选的bean。但是,如果你标示了两个或更多的首选bean,那么它就无法正常工作了。

设置首选bean的局限性在于@Primary无法将可选方案的范围限定到唯一一个无歧义性的选项中。它只能标示一个优先的可选方案。当首选bean的数量超过一个时,我们并没有其他的方法进一步缩小可选范围。与之相反,Spring的限定符能够在所有可选的bean上进行缩小范围的操作,最终能够达到只有一个bean满足所规定的限制条件。如果将所有的限定符都用上后依然存在歧义性,那么你可以继续使用更多的限定符来缩小选择范围。@Qualifier注解是使用限定符的主要方式。它可以与@Autowired@Inject协同使用,在注入的时候指定想要注入进去的是哪个bean。如果没有指定其他的限定符的话,所有的bean都会给定一个默认的限定符,这个限定符与beanID相同。我们可以为bean设置自己的限定符,而不是依赖于将bean ID作为限定符。在这里所需要做的就是在bean声明上添加@Qualifier注解。例如,它可以与@Component组合使用。值得一提的是,当通过Java配置显式定义bean的时候,@Qualifier也可以与@Bean注解一起使用。面向特性的限定符要比基于bean ID的限定符更好一些。但是,如果多个bean都具备相同特性的话,这种做法也会出现问题,此刻解决方法是:创建自定义的限定符注解,借助这样的注解来表达bean所希望限定的特性。这里所需要做的就是创建一个注解,它本身要使用@Qualifier注解来标注。

猜你喜欢

转载自blog.csdn.net/attack_breast/article/details/74933458