SpringBean的生命周期
有关Bean的生命周要从他们的作用域来区分。所谓的生命周期就是从 创建->使用->销毁
singlton(单例):从Spring 容器的创建到Spring容器的销毁。(如果是延时加载,在对象使用前创建对象。)
prototype(原型):在调用前创建,使用后销毁。
SpringBean是线程安全的吗,其作用域是什么?
在 Spring 中注入一个 Java 集合
Spring 提供了以下四种集合类的配置元素:
1: 该标签用来装配可重复的 list 值。
2: 该标签用来装配没有重复的 set 值。
3: 该标签可用来注入键和值可以为任何类型的键值对。
4: 该标签支持注入键和值都是字符串类型的键值对。
<beans>
<!-- Definition for javaCollection -->
<bean id="javaCollection" class="com.gupaoedu.JavaCollection">
<!-- java.util.List -->
<property name="customList">
<list>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>UK</value>
</list>
</property>
<!-- java.util.Set -->
<property name="customSet">
<set>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>UK</value>
</set>
</property>
<!-- java.util.Map -->
<property name="customMap">
<map>
<entry key="1" value="INDIA"/>
<entry key="2" value="Pakistan"/>
<entry key="3" value="USA"/>
<entry key="4" value="UK"/>
</map>
</property>
<!-- java.util.Properties -->
<property name="customProperies">
<props>
<prop key="admin">admin@gupaoedu.com</prop>
<prop key="support">support@gupaoedu.com</prop>
</props>
</property>
</bean>
</beans>
Spring的五种装配方式
no:这是 Spring 框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在 bean 定义中用标签明确的设置依赖关系。
byName:该选项可以根据 bean名称设置依赖关系。当向一个 bean中自动装配一个属性时,IOC容器将根据 bean 的名称自动在对应的容器中获取,如果找到就返回,没有找到就报错。
byType:该选项可以根据 bean 类型设置依赖关系。当向一个 bean中自动装配一个属性时,IOC容器将根据 bean 的名称自动在对应的容器中获取,如果找到就返回,没有找到就报错。
constructor:构造器的自动装配和 byType 模式类似,但是仅仅适用于与有构造器相同参数的 bean,如果在容器中没有找到与构造器参数类型一致的 bean,那么将会抛出异常。
autodetect:该模式自动探测使用构造器自动装配或者 byType 自动装配。首先,首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在 bean 内部没有找到相应的构 造器或者是无参构造器,容器就会自动选择 byTpe 的自动装配方式。
如何开启基于注解的自动装配?
1.引入配置文件中的下引入
<beans>
<context:annotation-config />
</beans>
在 bean 配置文件中直接引入 AutowiredAnnotationBeanPostProcessor
<beans>
<bean
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProc
essor"/>
</beans>
自动装配有哪些局限性?
重写:你仍然需要使用 和< property>设置指明依赖,这意味着总要重写自动装配。
原生数据类型:你不能自动装配简单的属性,如原生类型、字符串和类。
模糊特性:自动装配总是没有自定义装配精确,因此,如果可能尽量使用自定义装配。
请举例解释@Required 注入
主要用于校验某个bean的特定属性是否被正确的设置。如下:
public class EmployeeFactoryBean extends AbstractFactoryBean<Object>{
private String designation;
public String getDesignation() {
return designation;
}
@Required
public void setDesignation(String designation) {
this.designation = designation;
}
}
RequiredAnnotationBeanPostProcessor 是 Spring 中的后置处理用来验证被@Required 注解的 bean 属性是否被正确的设置了。如果没有找到对应的配置则会抛出BeanInitializationException
异常。
设置注入和构造注入
区别:注入的顺序、注入的时机、注入的有限性、循环依赖等问题。
1.在设值注入方法支持大部分的依赖注入,如果我们仅需要注入int、string和long型的变量,我们不要用设值的方法注入。对于基本类型,如果我们没有注入的话,可以为基本类型设置默认值。
在构造方法注入不支持大部分的依赖注入,因为在调用构造方法中必须传入正确的构造参数,否则的话为报错。
2.设值注入不会重写构造方法的值。如果我们对同一个变量同时使用了构造方法注入又使用了设置方法注入的话,那么构造方法将不能覆盖由设值方法注入的值。很明显,因为构造方法尽在对象被创建时调用。
3.在使用设值注入时有可能还不能保证某种依赖是否已经被注入,也就是说这时对象的依赖关系有可能是不完整的。而在另一种情况下,构造器注入则不允许生成依赖关系不完整的对象。
4.在设值注入时如果对象A和对象B互相依赖,在创建对象A时Spring会抛出ObjectCurrentlyInCreationException异常,因为在B对象被创建之前A对象是不能被创建的,反之亦然。所以Spring用设值注入的方法解决了循环依赖的问题,因对象的设值方法是在对象被创建之前被调用的。
Spring 框架中有哪些不同类型的事件?
五种:ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent、RequestHandledEvent。
ContextRefreshedEvent
该事件会在 ApplicationContext 被初始化或者更新时发布。也可以在调用 ConfigurableApplicationContext 接口中的 refresh()方法时被触发。
ContextStartedEvent
当容器调用 ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
ContextStoppedEvent
当容器调用 ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
ContextClosedEvent
当 ApplicationContext 被关闭时触发该事件。容器被关闭时,其管理的所有单例 Bean 都被销毁。
RequestHandledEvent
在 Web 应用中,当一个 http 请求(request结束触发该事件)
还可以通过扩展 ApplicationEvent 类来开发自定义的事件。
定义
public class CustomApplicationEvent extends ApplicationEvent{
public CustomApplicationEvent ( Object source, final String msg ){
super(source);
System.out.println("Created a Custom event");
}
}
监听
public class CustomEventListener implements ApplicationListener <
CustomApplicationEvent >{
@Override
public void onApplicationEvent(CustomApplicationEvent applicationEvent) {
//handle event
}
}
发布
CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext,
“Test message”);
applicationContext.publishEvent(customEvent);
FileSystemResource 、 ClassPathResource 、ServletContextResource有何区别?
FileSystemResource
FileSystemResource 是 Spring 提供的资源访问类。FileSystemResource 类相比其他两个资源访问类,没有什么优势,它只是在 File 类的基础上略作封装。
/*默认从文件系统的当前路径加载xttblog.xml资源*/
FileSystemResource fsr = new FileSystemResource("xttblog.xml");
类图
FileSystemResource
部分源码
public class FileSystemResource extends AbstractResource implements WritableResource {
private final File file;
private final String path;
public FileSystemResource(File file) {
Assert.notNull(file, "File must not be null");
this.file = file;
this.path = StringUtils.cleanPath(file.getPath());
}
public FileSystemResource(String path) {
Assert.notNull(path, "Path must not be null");
this.file = new File(path);
this.path = StringUtils.cleanPath(path);
}
/**
* Return the file path for this resource.
*/
public final String getPath() {
return this.path;
}
/**
* This implementation returns whether the underlying file exists.
* @see java.io.File#exists()
*/
@Override
public boolean exists() {
return this.file.exists();
}
.....
}
FileSystemResource 可以看出有两种构造,一种是文件,一种是字符串。
ClassPathResource
利用ClassPathResource读取xml配置的基本思路就是通过构造函数传入的文件路径,接着交给class或者classLoader,调用getResourceAsStream获取到InputStream。
FileSystemResource 和 ClassPathResource 的用法如下:
public class Test {
String filePath = "D:/com/xttblog.txt";
//使用系统文件路径方式加载文件
Resource res1 = new FileSystemResource(filePath);
//使用类路径方式加载文件
Resource res2 = new ClassPathResource("conf/xttblog.txt");
InputStream ins1 = res1.getInputStream();
InputStream ins2 = res2.getInputStream();
getFileName();//获取文件名
getFile();//获取资源对应的File对象
getInputStream();//获取文件的输入流
createRelative(String relativePath);//在相对地址创建新文件
EncodedResource encRes = new EncodedResource(res, "UTF-8");
String content = FileCopyUtils.copyToString(encRes.getReader());
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resources[] = resolver.getResources("classpath*://com/***/*.xml");
For(Resource resource : resources){
System.out.println(resource.getDescription);
}
}
类图
image.png源码
public class ClassPathResource extends AbstractFileResolvingResource {
private final String path;
@Nullable
private ClassLoader classLoader;
@Nullable
private Class<?> clazz;
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
public ClassPathResource(String path, @Nullable Class<?> clazz) {
Assert.notNull(path, "Path must not be null");
this.path = StringUtils.cleanPath(path);
this.clazz = clazz;
}
@Deprecated
protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz) {
this.path = StringUtils.cleanPath(path);
this.classLoader = classLoader;
this.clazz = clazz;
}
/**
* Return the path for this resource (as resource path within the class path).
*/
public final String getPath() {
return this.path;
}
/**
* Return the ClassLoader that this resource will be obtained from.
*/
@Nullable
public final ClassLoader getClassLoader() {
return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);
}
@Override
public boolean exists() {
return (resolveURL() != null);
}
@Nullable
protected URL resolveURL() {
if (this.clazz != null) {
return this.clazz.getResource(this.path);
}
else if (this.classLoader != null) {
return this.classLoader.getResource(this.path);
}
else {
return ClassLoader.getSystemResource(this.path);
}
}
@Override
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
}
else if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
}
else {
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
}
return is;
}
@Override
public URL getURL() throws IOException {
URL url = resolveURL();
if (url == null) {
throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
}
return url;
}
@Override
public Resource createRelative(String relativePath) {
String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
return (this.clazz != null ? new ClassPathResource(pathToUse, this.clazz) :
new ClassPathResource(pathToUse, this.classLoader));
}
@Override
@Nullable
public String getFilename() {
return StringUtils.getFilename(this.path);
}
@Override
public String getDescription() {
StringBuilder builder = new StringBuilder("class path resource [");
String pathToUse = path;
if (this.clazz != null && !pathToUse.startsWith("/")) {
builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
builder.append('/');
}
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
builder.append(pathToUse);
builder.append(']');
return builder.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof ClassPathResource) {
ClassPathResource otherRes = (ClassPathResource) obj;
return (this.path.equals(otherRes.path) &&
ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) &&
ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz));
}
return false;
}
@Override
public int hashCode() {
return this.path.hashCode();
}
}
区别如下:
ClassPathResource:从系统的类路径中加载
FileSystemResource:从文件系统加载,比如说自己指定配置文件的全路径
InputStreamResource:从输入流中加载
ServletContextResource:从Servlet 上下文环境中加载
UrlResource:从指定的Url加载
Class.getResource("")获取的是相对于当前类的相对路径。Class.getResource("/")获取的是classpath的根路径。ClassLoader.getResource("")获取的是classpath的根路径。
在创建ClassPathResource对象时,我们可以指定是按Class的相对路径获取文件还是按ClassLoader来获取。
FileSystemResource 效果类似于Java中的File
ClassPathResource 效果类似于this.getClass().getResource("/").getPath();
ServletContextResource 效果类似于request.getServletContext().getRealPath("");
Spring 框架中都用到了哪些设计模式?
很多很多很多
1、代理模式:在 AOP 和 remoting 中被用的比较多。
2、单例模式:在 spring 配置文件中定义的 bean 默认为单例模式。
3、模板模式:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
4、委派模式:Spring 提供了 DispatcherServlet 来对请求进行分发。
5、工厂模式:BeanFactory 用来创建对象的实例,贯穿于 BeanFactory / ApplicationContext
接口的核心理念。
6、代理模式:AOP 思想的底层实现技术,Spring 中采用 JDK Proxy 和 CgLib 类库。
Spring5 新特性
1、依赖 JDK 8+和 Java EE7+以上版本
2、首次采用反应式编程模型
3、支持使用注解进行编程
4、新增函数式编程
5、支持使用 REST 断点执行反应式编程
6、支持 HTTP 2.0
7、新增 Kotlin 和 Spring WebFlux
8、可使用 Lambda 表达式注册 Bean
9、Spring WebMVC 支持最新的 API
10、使用 JUnit5 执行条件和并发测试
11、使用 Spring WebFlux 执行集成测试
12、核心容器优化
网友评论