spring实战第四版
第一章: 对spring进行一个大致的概括。
第二章:关于装配bean
文章目录
前言
为了加强对spring的深刻理解,本周开始看spring实战第四版的内容。本文描述的内容主要包括第一章的spring的bean容器。第二章的关于装配bean的问题。
提示:以下是本篇文章正文内容,下面案例可供参考
一、spring的作用?
spring可以做到很多事情,这些都基于他的两个核心特性,一个是依赖注入(DI),一个就是面向切面编程(AOP)。
1.关于简化开发
关于简化开发就不得不提到AOP,DI可以让相互协作的软件组件你得到松散耦合的,而面向切面编程允许你把遍布应用各处的功能分离出来而形成可重用的技术。
例如:
2.关于bean的容器
容纳你的bean。
spring容器并不是只有一个。spring自带了多个容器实现,可以分为两中不同的类型。bean工厂是最简单的容器,提供基本的DI容器。还有一种是上下文的形式,这个形式是基于BeanFactory来构建的,提供应用框架级别的服务。
关于应用上下文作一个展开的详解。
AnnotationConfigApplicationContext:从一个或多个基于java的配置类中加载spring应用上下文。
AnnotationConfigWebApplicationContext:从一个或者多个基于java的配置类中加载Spring Web应用上下文。
ClassPathXmlApplicationContext:从一个类路径下的一个或者多个xml配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
FileSystemXmlapplicationcontext:从文件系统下一个或多个基于xml的配置文件加载上下文的定义。
XmlWebApplicationContext:从web应用于一个或多个xml的配置文件中加载上下文定义。
关于bean的生命周期:
在传统java中,bean的生命周期很简单,使用new关键字对bean进行实例化之后bean就可以开始使用了,当bean不再被使用的时候,则由java自动进行垃圾回收。
在spring中则不是这样,在spring中bean的生命周期显得比较复杂。
二、装配bean
在第二个模块主要写的内容是关于自动化到装配bean,通过java代码装配bean,通过xml来装配bean这几个方面来展开。
1.自动化装配bean
spring是从两个角度来自动化装配bean的;
角度一
组件扫描:Spring会自动发现应用上下文中创建的bean。
自动装配:Spring自动满足bean之间的依赖。
那么关于如何注册bean,通常有八种方式:
bean的加载方式一:
通过xml的方式来申明。直接在启动类里通过getbean的方法来直接获取。既可以声明自定义的bean,也可以声明第三方的bean。太繁琐。
bean的加载方式二
@Comment这个注解带标类bean标签。需要再xml层里面指定加载bean的位置。在使用这种方式来加载第三方的bean里时,需要写一个配置类,在这个配置类里声明你的第三方的bean。配置类里添加@bean 和 @Comment的注解。
bean的加载方式三:
将配制文件改成了配置类。只要使用AnnotationConfigApplicationContext来加载了一个类,那么这个类就会被自动声明成一个bean。
扩展关于FactoryBean
工厂bean。
在实现了FactoryBean的这个接口之后,它声明对象制造bean的时候,它制造的不是它本身,是一个它的泛型。
关于Comment以及Configuration之间的差别。
Configuration创建代理对象。当把它的proxyBeanMethod属性设置为flase时,创建的就不是一个代理对像了。
bean的加载方式四:
使用@Import的方式,在这个注解内设置你要读取的类。如果使用这种方式来加载,配置类可以不使用注解。
bean的加载方式五:
使用register的方式来手工的加载一个bean。这个后面的注册的bean会覆盖前面的bean。注册bean甚至可以使用register直接传入一个class就可以注册完成。
bean的加载方式六
实现一个名为ImportSelector的接口。是一个选择器,你可以进行各种各样的判断。不仅可以加载bean,更可以控制加载那个bean。
bean的加载方式七:
实现一个ImportBeanDefinitionRegistrar接口,
bean的加载方式八
实现一个BeanDefinitionRegistrtPostProcessor接口。
在自动装配完bean之后,我们要对自动装配进行一个验证
2.通过java代码装配bean
尽管在很多情况通过组件扫描和自动装配来实现spring的自动装配是更为推荐的方案,但一些特殊情况下自动化配置的方案是行不通的,这时候就需要明确配置spring,所以我们来简述一下使用java代码来配置bean。
举例说明一种情况:如果你想将第三方的组件装配到你的应用中,在这种情况下是没有办法在它到类上添加@Comment和@Autowired这些注解的,这个时候就不能再使用自动装配这种了。在这种情况下时我们就必须使用显式配置的方法来进行装配。
在进行显式配置的时候,javaConfig是更好的方案。
使用java来装配bean的时候
1.创建配置类
@Configuration
public class CDPlayerConfig{
}
声明简单的bean
@Bean
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}
借助JavaConfig实现注入
@Bean
public COPlayer cdPlayer(){
return new CDPlayer(sgtPeppers())
}
假如对sgtPeppers这个方法的调用跟其他java方法调用一样的话,那么每一个CDOlayer实例就都会有一个自己特有的sgtPepper实例,在软件领域,我们完全可以将同一个SgtPepper实例注入到任意数量的其他的bean之中。默认情况下,spring中的bean都是单例的,我们不会也没有必要为第二个bean创建完全一样的实例对象,所以spring会拦截对sgtPepper的调用并确保返回的是spring创建的bean,也就是spring本身在调用sgtPepper是所创建的bean。
这样理解起来通过调用方式来调用来饮用bean的方式有点令人困惑,其实还有一种理解起来更为简单的办法。
@Bean
public CDPlayer cdplayer(CompactDisc compactDisc){
return new CDPlayer(comPlayerDisc)
}
3.通过xml装配bean
通过xml文件来为spring装配bean前,你需要创建一个新的配置规范,在使用JavaConfig的时候意味着要创建一个带有@Configuration注解的类,而在xml文件中,这意味着要创建一个xml文件,并且要以元素为根。
简单的xml文件的实例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
只需要配置FactoryBean即可
真正交给IOC容器管理的对象,是FactoryBean工厂中getObject方法返回的对象
-->
<bean class="org.example.factory.UserFactoryBean"></bean>
</beans>
类似如上实例的xml文件的写法,包裹在之中。
我们可以很容易的看出来,这个基本的xml文件的配置已经要比同等功能的JavaConfig类要复杂许多了,作为起步来看,JavaConfig只需要一个@Configuration,但在使用xml文件时,需要在配置文件的顶部声明多个xml模式文件。
使用xml文件装配bean
1.声明一个简单的bean
<bean class="soundsystem.SgtPepper"/>
上面声明了一个简单的bean,创建这个bean的类是通过class属性来指定的,并且要使用全限定的类名。
借助构造器注入初始化bean
在springXML配置中,只有一种声明bean的:使用并指定class属性。spring会从这里获取必要的信息来创造bean。但是,在XML中声明DI时,会有多种可选配置方案和风格。具体到构造器注入,有两种基本的配置方案可供选择。
1.元素
2.使用Spring3.0所引入的c-命名·空间。
两者的区别在很大程度就是是否冗长繁琐,在使用的过程中,元素比使用c-命名空间更加冗长,从而导致XML文件更加难懂,另外有些事情可以做到,但是c-命名空间无法做到。
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc"/>
</bean>
作为替代方案,你也可以使用Spring的c-命名空间,代码如下所示
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">
...
</beans>
在c-命名空间和模式声明之后,我们就可以用它来声明构造器参数。
<bean id="cdPlayer" class="soundsystem.CDPlay">
c:cd-ref="compactDisc"/>
之后需要将字面量注入到构造器当中。
package com.itheima;
public class BlackDisc implements CompactDisc{
private String title;
private String artist;
public BlackDisc(String title, String artist) {
this.title = title;
this.artist = artist;
}
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
设置属性
package com.itheima;
import org.springframework.beans.factory.annotation.Autowired;
public class CDPlayer implements MediaPlayer{
private CompactDisc compactDisc;
@Autowired
public void setCompactDisc(CompactDisc compactDisc){
this.compactDisc = compactDisc;
}
public void play(){
compactDisc.play();
}
}
那么该如何选择构造器注入还是属性注入?
其实按照作者的观点,对于强依赖就使用构造器注入,而对可选性的依赖就选择使用属性。
除了c-命名空间,spring还提供了更加简便的p-命名空间,为了启用p-命名空间,必须要在xml文件中与其他的命名空间进行一起对比声明。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
字面量也可注入到属性中;
package com.itheima;
import java.util.List;
public class BlankDisc implements CompactDisc{
private String title;
private String artist;
private List<String> tracks;
public BlankDisc(String title, String artist, List<String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
public void setTitle(String title) {
this.title = title;
}
public void setArtist(String artist) {
this.artist = artist;
}
public void setTracks(List<String> tracks) {
System.out.println("Plating"+title+"with"+artist);
for (String track : tracks) {
System.out.println("-"+track);
}
}
}
扩展:导入和混合配置
在典型的spring中。我们第一时间想到的是使用自动化装配或者是显式配置。但有时xml配置的方法确实属于最优选择,所以你尽可以将通过JavaConfig的组件扫描和自动装配和xml配置混合在一起,进行一次混合配置。
首先是在JavaConfig中引用xml配置文件。
package com.itheima;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CDConfig {
//配置CD
@Bean
public CompactDisc compactDisc(){
return new MyCompactDisc();
}
}
如上面代码所示,compactDisc方法已经从这个config中移除了,但我们也有方法来使这两个类组合在一起。
package com.itheima;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig {
//CDPlayerConfig类中不需要定义任何bean,因为CDConfig类中已经定义了CDPlayer和CompactDisc的bean
@Bean
public CDPlayer cdPlayer(CompactDisc cd) {
return new CDPlayer(cd);
}
}
在xml文件中引入JavaConfig
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="b.xml"/>
<bean id="person" class="com.example.springdemo.Person" c:name="张三" c:age="18">
<property name="address" ref="address"/>
</bean>
</beans>
还有就是本周在实验thingliks的平台的时候。遇到了一系列的问题。问题陈列如下。
1.
thinglinks.mqttsnet.com 2024-09-05 17:40:19 [com.alibaba.nacos.client.Worker] ERROR com.alibaba.nacos.client.security.SecurityProxy - login failed: {"code":500,"message":"caused: User nacos not found;","header":{"header":{"Accept-Charset":"UTF-8","Connection":"close","Content-Length":"29","Content-Security-Policy":"script-src 'self'","Content-Type":"text/html;charset=UTF-8","Date":"Thu, 05 Sep 2024 09:40:19 GMT","Vary":"Access-Control-Request-Headers"},"originalResponseHeader":{"Connection":["close"],"Content-Length":["29"],"Content-Security-Policy":["script-src 'self'"],"Content-Type":["text/html;charset=UTF-8"],"Date":["Thu, 05 Sep 2024 09:40:19 GMT"],"Vary":["Access-Control-Request-Headers","Access-Control-Request-Method","Origin"]},"charset":"UTF-8"}}
thinglinks.mqttsnet.com 2024-09-05 16:21:47 [Thread-1] WARN com.alibaba.nacos.common.http.HttpClientBeanHolder - [HttpClientBeanHolder] Start destroying common HttpClient
thinglinks.mqttsnet.com 2024-09-05 16:21:47 [Thread-7] WARN com.alibaba.nacos.common.notify.NotifyCenter - [NotifyCenter] Start destroying Publisher
thinglinks.mqttsnet.com 2024-09-05 16:24:09 [Thread-7] WARN com.alibaba.nacos.common.notify.NotifyCenter - [NotifyCenter] Start destroying Publisher
thinglinks.mqttsnet.com 2024-09-05 16:24:09 [Thread-1] WARN com.alibaba.nacos.common.http.HttpClientBeanHolder - [HttpClientBeanHolder] Start destroying common HttpClient
thinglinks.mqttsnet.com 2024-09-05 16:24:09 [Thread-7] WARN com.alibaba.nacos.common.notify.NotifyCenter - [NotifyCenter] Destruction of the end
thinglinks.mqttsnet.com 2024-09-05 16:24:09 [Thread-1] WARN com.alibaba.nacos.common.http.HttpClientBeanHolder - [HttpClientBeanHolder] Destruction of the end
在配置这个物联网平台的时候,这个物联网平台是一个使用分布式来写的,服务拆分成了多个微服务,微服务除了几个特殊的,其他都可以选择性的启动,当然,这需要使用到nocos注册中心,在nacos注册中心导入配置的时候,会出现导入配置不合法的提示信息,导致无法上传配置文件,解决方法如下所示;
问题原因:在另外的命名空间里导出了一个配置,查看发现,导出配置的包里有个DEFAULT_GROUP的文件夹,原来是在配件文件的上一级目录需要指定分组,而我要上传的配置包里没有指定分组。
解决办法:创建一个文件夹,命名为指定的分组,把配置文件放进去,打包,进入nacos,导入配置,导入成功。
这个文件夹要打包成zip文件的形式,一定要把整个默认分组的文件夹打包成zip文件,然后上传就OK了。
报错信息还有待解决。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了spring实战里面的内容,同样也写到了本周遇到的一点问题以及部分问题的解决方案,同样也列举出了一些报错信息,如果你遇到了类似的问题,欢迎和我讨论。