@yexiaoqi
2021-05-23T21:41:52.000000Z
字数 6832
阅读 1148
java面试总结
DefaultListableBeanFactory
DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载bean的默认实现,XmlBeanFactory继承DefaultListableBeanFactory并扩展。
XmlBeanDefinitionReader
读取XML配置文件,解析载入的Bean定义的资源文件,解析过后的BeanDefinition在IoC容器中的注册
Resource 定位:我们一般使用外部资源来描述 Bean 对象,所以 IOC 容器第一步就是需要定位 Resource 外部资源 。Resource 的定位其实就是 BeanDefinition 的资源定位,它是由 ResourceLoader 通过统一的 Resource 接口来完成的,这个 Resource 对各种形式的 BeanDefinition 的使用都提供了统一接口 。
载入:第二个过程就是 BeanDefinition 的载入 ,BeanDefinitionReader 读取 , 解析 Resource 定位的资源,也就是将用户定义好的 Bean 表示成 IOC 容器的内部数据结构也就是 BeanDefinition, 在 IOC 容器内部维护着一个 BeanDefinitionMap 的数据结构,通过这样的数据结构, IOC 容器能够对 Bean 进行更好的管理 。 在配置文件中每一个都对应着一个 BeanDefinition 对象 。
注册:第三个过程则是注册,即向 IOC 容器注册这些 BeanDefinition,这个过程是通过 BeanDefinitionRegistery 接口来实现的 。
BeanFactory 是 Spring 里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和获取对象的功能 。
两者装载 bean 的区别
延迟实例化
优点: 应用启动时占用资源很少,对资源要求较高的应用,比较有优势。
缺点:速度会相对来说慢一些 。 而且有可能会出现空指针异常的错误,而且通过 bean 工厂创建的 bean 生命周期会简单一些。 所有的 Bean 在启动的时候都加载,系统运行的速度快,而且可以尽早的发现系统中的配置问题 。
SpringBoot 用于简化Spring开发的。
src/main/resiurces:application*.yml
src/main/resiurces:application*.yaml
src/main/resiurces:application*.properties
Spring Boot创建一个简单的Web项目很简洁,不需要太多配置
@SpringBootApplication
public class ConfigApplication{
public static void main(String[] args){
SpringApplication.run(ConfigApplication.class, args);
}
}
查看run
方法(省略不关键的部分代码):
public COnfigurableApplicationContext run(String... args){
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
listeners.finished(context, null); return context;
}catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
它首先开启一个SpringApplicationRunListeners
监听器,让后创建一个应用上下文ConfigurableApplicationContext
,通过这个上下文加载应用所需的类和各种环境配置等。
下面看createApplicationContext
方法加载应用定义的和需要的类及各种资源。
所有的自动配置都从@SpringBootApplication
引入的,它又包含了Configuration
、@EnableAutoConfiguration
和@ComponentScan
,其中,@EnableAutoConfiguration
就是启用自动配置的,并将导入一些自动配置类定义。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
)} )
public @interface SpringBootApplication {
Class<?>[] exclude() default {};
String[] excludeName() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
}
@EnableAutoConfiguration
中导入了AutoConfigurationImportSelector
类,此类中SpringFactoriesLoader.loadFactoryNames 方法的作用就是从META-INF/spring.factories
文件中读取指定类对应的类名称列表 ,列表中的自动配置类很多,这些配置类中大多数都将导入,并处于被备用状态,当项目中引入了相关的包时,相关功能将会被启用。
例如在项目的maven配置中配置了Redis的引用,Redis的默认配置项将被启用,首先会读取项目中的配置,只有项目中没有相关配置才启用配置的默认值,下面代码是Redis的自动配置,如果配置文件中没设置,会使用下面默认设置。
@ConfigurationProperties(
prefix = "spring.redis"
)
public class RedisProperties {
private int database = 0;
private String host = "localhost";
private String password;
private int port = 6379;
private int timeout;
private RedisProperties.Pool pool;
private RedisProperties.Sentinel sentinel;
private RedisProperties.Cluster cluster;
public RedisProperties(){
}
}
通过自动配置,就不用重复定义配置项名称了,覆盖约定的配置项即可。可通过查看各个Properties类,查看有哪些配置项。
@SpringBootApplication:就是三个注解放一起,@SpringBootConfiguration
,@EnableAutoConfiguration
以及@ComponntScan
的组合。
@SpringBootConfiguration:此注解实际上和@Configuration
有相同作用,配置了该注解的类就能够以JavaConfig的方式完成一些配置,可以不再使用XML配置。
@ComponentScan:此注解完成的是自动扫描的功能,相当于Spring XML配置文件中的:
<context:component-scan>
可以使用basePackages属性指定要扫描的包,以及扫描的条件。若不设置,默认扫描@ComponentScan
注解所在类的统计类和同级目录下的所有类。
@EnableAutoConfiguration:这个注解是让Spring Boot的配置能够如此简化的关键性注解。
可以不需要,内置了Tomcat等容器。
Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。
Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。具体请看这篇文章《Spring Boot Starters启动器》。
注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。
具体看这篇文章《Spring Boot自动配置原理、实战》。
服务在发布时 指定对应的服务名(服务名包括了IP地址和端口) 将服务注册到注册中心(eureka或者zookeeper)。这一过程是springcloud自动实现 只需要在main方法添加@EnableDisscoveryClient 同一个服务修改端口就可以启动多个实例
调用方法:传递服务名称通过注册中心获取所有的可用实例 通过负载均衡策略调用(ribbon和feign)对应的服务
1. 基于面向接口的动态代理方式生成实现类
2. 根据接口类的注解声明规则,解析出底层MethodHandler
3. 基于RequestTemplate,动态生成Request
4. Encoder Request请求
5. 拦截器负责对请求和返回进行拦截处理、日志记录
7. 基于重试器发送http请求,可基于不同的框架处理
#{} 是占位符,${} 是拼接符
答:第一种是使用<resultMap>
标签,逐一定义列名和对象属性名之间的映射关系。第二种是使用sql列的别名功能,将列别名书写为对象属性名
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
方法1:通过@Param
注解获取参数
public User selectUser(@Param("userName") String name, @Param("deptId") int deptId);
<select id="selectUser" resultMap="UserResultMap">
select * from user where user_name = #{userName} and dept_id = #{deptId}
</select>
#{}
里面的名称对应的是注解@Param
括号里面修饰的名称。
这种方法在参数不多的情况还是比较直观的,推荐使用。
方法2:通过Map获取参数
public User selectUser(Map<String, Object> params);
<select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">
select * from user where user_name = #{userName} and dept_id = #{deptId}
</select>
#{}
里面的名称对应的是Map
里面的key名称。
这种方法适合传递多个参数,且参数易变能灵活传递的情况。
方法3:通过Java Bean获取参数
public User selectUser(Map<String, Object> params);
<select id="selectUser" parameterType="com.test.User" resultMap="UserResultMap">
select * from user where user_name = #{userName} and dept_id = #{deptId}
</select>
#{}
里面的名称对应的是User
类里面的成员属性。
这种方法很直观,但需要建一个实体类,扩展不容易,需要加属性,看情况使用。