Java每日面试题5题(二)—— Spring相关篇二

一、Autowired和Resource关键字的区别

@Autowired和@Resource注解都是对Bean注入时使用的,@Resource并不是Spring自带的注解,是javax.annotation包下的注解,但是Spring支持该注解的注入

  • 共同点

两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。

  • 不同点

(1)@Autowired是Spring提供的注解,只按照byType注入,两种使用方式

public class TestServiceImpl {
    
    
    // 下面两种@Autowired使用方式使用一种即可
    
    @Autowired
    private UserDao userDao; // 用于字段上

    @Autowired
    public void setUserDao(UserDao userDao) {
    
     // 用于属性的方法上
        this.userDao = userDao;
    }
}

@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如
果允许null值,可以设置它的required属性为false

public class TestServiceImpl {
    
    

    @Autowired(required = false)
    private UserDao userDao;
}

如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用

public class TestServiceImpl {
    
    

    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
}

(2)@Resource注解

默认按照ByName自动注入,由J2EE提供,需要导入包 javax.annotation.Resource

@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略

public class TestServiceImpl {
    
    
 
    // 下面两种@Resource只要使用一种即可
 
    @Resource(name = "userDao")
    private UserDao userDao; // 用于字段上

    @Resource(name = "userDao")
    public void setUserDao(UserDao userDao) {
    
     // 用于属性的setter方法上
        this.userDao = userDao;
    }
}

@Resource装配顺序:

  1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛
    出异常
  2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
  3. 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会
    抛出异常
  4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,
    则回退为一个原始类型进行匹配,如果匹配则自动装配
  • 总结

@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。

Spring基于xml注入bean的几种方式?

  • Set方法注入
  • 构造器注入
  • 静态工厂注入
  • 实例工厂注入

Spring框架中都用到了哪些设计模式?

  • 简单工厂模式

Spring 中的 BeanFactory 就是简单工厂模式的体现。根据传入一个唯一的标识来获得 Bean 对象,但是在传入参数后创建还是传入参数前创建,要根据具体情况来定

  • 工厂模式

Spring 中的 FactoryBean 就是典型的工厂方法模式,实现了 FactoryBean 接口的 bean是一类叫做 factory 的 bean。其特点是,spring 在使用 getBean() 调用获得该 bean 时,会自动调用该 bean 的 getObject() 方法,所以返回的不是 factory 这个 bean,而是这个 bean.getOjbect()方法的返回值

  • 单例模式

在 spring 中用到的单例模式有: scope="singleton" ,注册式单例模式,bean 存放于Map 中。bean name 当做 key,bean 当做 value

  • 原型模式

在 spring 中用到的原型模式有: scope="prototype" ,每次获取的是通过克隆生成的新实例,对其进行修改时对原有实例对象不造成任何影响

  • 迭代器模式

在 Spring 中有个 CompositeIterator 实现了 Iterator,Iterable 接口和 Iterator 接口,这两个都是迭代相关的接口。可以这么认为,实现了 Iterable 接口,则表示某个对象是可被迭代的。Iterator 接口相当于是一个迭代器,实现了 Iterator 接口,等于具体定义了这个可被迭代的对象时如何进行迭代的

  • 代理模式

Spring 中经典的 AOP,就是使用动态代理实现的,分 JDK 和 CGlib 动态代理

  • 适配器模式

Spring 中的 AOP 中 AdvisorAdapter 类,它有三个实现:MethodBeforAdviceAdapter、AfterReturnningAdviceAdapter、ThrowsAdviceAdapter。Spring会根据不同的 AOP 配置来使用对应的 Advice,与策略模式不同的是,一个方法可以同时拥有多个Advice。Spring 存在很多以 Adapter 结尾的,大多数都是适配器模式

  • 观察者模式

Spring 中的 Event 和 Listener。spring 事件:ApplicationEvent,该抽象类继承了EventObject 类,JDK 建议所有的事件都应该继承自 EventObject。spring 事件监听器:ApplicationListener,该接口继承了 EventListener 接口,JDK 建议所有的事件监听器都应该继承 EventListener

  • 模板模式

Spring 中的 org.springframework.jdbc.core.JdbcTemplate 就是非常经典的模板模式的应用,里面的 execute 方法,把整个算法步骤都定义好了

  • 责任链模式

DispatcherServlet 中的 doDispatch() 方法中获取与请求匹配的处理器HandlerExecutionChain,this.getHandler() 方法的处理使用到了责任链模式

  • more

其他还有其他模式没列出来,面试时可选择性的回答,回答自己熟悉的,避免一问三不知就尴尬了

Spring 中 ApplicationContext 和 BeanFactory 的区别?

  • 包目录不同

BeanFactory -->> 是 spring-beans.jar 包的org.springframework.beans.factory.BeanFactory

ApplicationContext -->> 是spring-context.jar 包的org.springframework.context.ApplicationContext

  • 国际化

BeanFactory 是不支持国际化功能的,因为 BeanFactory 没有扩展 Spring 中 MessageResource接口。相反,由于 ApplicationContext 扩展了 MessageResource 接口,因而具有消息处理的能力

  • 强大的事件机制

基本上牵涉到事件(Event)方面的设计,就离不开观察者模式,ApplicationContext 的事件机制主要通过 ApplicationEvent 和 ApplicationListener 这两个接口来提供的,和 Java swing 中的事件机制一样。即当 ApplicationContext 中发布一个事件时,所有扩展了 ApplicationListener 的 Bean都将接受到这个事件,并进行相应的处理

  • 底层资源的访问

ApplicationContext 扩展了 ResourceLoader(资源加载器)接口,从而可以用来加载多个Resource,而 BeanFactory 是没有扩展 ResourceLoader

  • 对Web的支持

与 BeanFactory 通常以编程的方式被创建,ApplicationContext 能以声明的方式创建,如使用ContextLoader

  • 延迟加载
  1. BeanFactroy 采用的是延迟加载形式来注入 Bean 的,即只有在使用到某个 Bean 时( 调用 getBean()),才对该 Bean 进行加载实例化。这样,我们就不能发现一些存在的 spring 的配置问题。而 ApplicationContext 则相反,它是在容器启动时,一次性创建了所有的 Bean。这样,在容器启动时,我们就可以发现 Spring 中存在的配置错误
  2. BeanFactory 和 ApplicationContext 都支持 BeanPostProcessor、BeanFactoryPostProcessor 的使用。两者之间的区别是:BeanFactory 需要手动注册,而 ApplicationContext 则是自动注册
  • 总结

可以看到,ApplicationContext 继承了 BeanFactory,BeanFactory 是 Spring 中比较原始的Factory,它不支持 AOPWeb 等 Spring 插件。而 ApplicationContext 不仅包含了 BeanFactory的所有功能,还支持 Spring 的各种插件,还以一种面向框架的方式工作以及对上下文进行分层和实现继承

BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;而 ApplicationContext 面向使用Spring 的开发者,相比 BeanFactory 提供了更多面向实际应用的功能,几乎所有场合都可以直接使用 ApplicationContext,而不是底层的 BeanFactory

Spring 框架中的单例 Bean 是线程安全的么?

Spring 框架并没有对单例 Bean 进行任何多线程的封装处理,关于单例 Bean 的线程安全和并发问题,需要开发者自行去搞定

单例的线程安全问题,并不是 Spring 应该去关心的。Spring 应该做的是,提供根据配置,创建单例 Bean 或多例 Bean 的功能

当然,但实际上,大部分的 Spring Bean 并没有可变的状态,所以在某种程度上说 Spring 的单例Bean 是线程安全的。如果你的 Bean 有多种状态的话,就需要自行保证线程安全。最浅显的解决办法,就是将多态 Bean 的作用域(Scope)由 Singleton 变更为 Prototype

猜你喜欢

转载自blog.csdn.net/weixin_47971206/article/details/125239418
今日推荐