@yexiaoqi
2021-05-23T13:41:52.000000Z
字数 6832
阅读 1432
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*.ymlsrc/main/resiurces:application*.yamlsrc/main/resiurces:application*.propertiesSpring Boot创建一个简单的Web项目很简洁,不需要太多配置
@SpringBootApplicationpublic 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类里面的成员属性。
这种方法很直观,但需要建一个实体类,扩展不容易,需要加属性,看情况使用。