二.JavaEE&框架&中间件
数据库基础
平局值用什么,分组用什么
统计平局值:avg , 分组:group by
两个相同列的结果集求并集用什么
union 并集 , union all(允许重复并集)
完整查询SQL中的关键字的定义顺序
SELECT 列名 FROM 表1 JOIN 表2 ON 条件 WHERE 条件 GROUP BY 列名 HAVING 条件 ORDER BY 列名 LIMIT
完整的多表JOIN查询,SQL中关键字的执行顺序
FROM --> ON --> JOIN --> WHERE --> GROUP BY --> HAVING --> ORDER BY --> LIMIT
员工表employee字段有: id, username, amount ,deptname .
- 求每个部门总人数怎么做 ,
select 部门名,count(id) from employee group by deptname
- 求每个部门总工资怎么做?
select 部门名,sum(amount) from employee group by deptname
Spring部分
介绍一下Spring
Spring是一个开源的轻量级控制反转和面向切面编程的容器框架。轻量级是说它开发使用简单,功能强大。控制反转是指将对象的创建,销毁控制交给ioc容器,方便解耦合,降低维护难度,面向切面编程是指将相同的逻辑横向抽取出来,可以对一些通用业务如事务,日志进行集中管理
说下Spring框架的组成
- CoreContain核心容器模块:
- spring-core:提供框架的基本组成部分,包括 IoC 和依赖注入功能
- spring-beans:提供 BeanFactory,工厂模式
- context:提供国际化,事件传播,资源加载等功能
- spring-ExpressionLanguage:提供表达式语言
- Web模块
- Web:提供面向web的基本功能和面向web的应用上下文
- Web-MVC:为web应用提供模型视图控制(MVC)
- Web-Socket:在 web 应用程序中提供客户端和服务器端之间通信的方式
- Web-Portlet:模块提供了用于Portlet环境的MVC实现
- 数据/集成模块
- JDBC:包含了Spring对JDBC数据访问进行封装的所有类
- ORM:为对象-关系映射提供交互层
- OXM:提供对Object/XML映射实现的抽象层
- JMS:主要包含了一些制造、消费和消息的功能
- Transaction:为实现特殊接口类以及所有的 POJO 支持编程式和声明式的事务管理
- 其他模块
- AOP:提供了面向切面编程相关实现
- Aspects:模块提供了与AspectJ的集成,是一个功能强大的AOP框架
- Instrumentation:提供了class instrumentation 的支持和类加载器classloader的实现
- Messaging:为 STOMP 提供支持
- Test:支持使用JUnit和TestNG对Spring组件进行测试
什么是Spirng的IOC
IOC控制反转,把对象的创建,属性设置,初始化,销毁等工作交给Spirng的IOC容器去管理,解放程序员的劳动力。
对象被注册到Spring的IOC容器中,使用的时候从容器中获取即可,非常方便。
它通过依赖注入,将需要的外部资源注入到组件中,使用IOC使得对象之间的耦合度降低,资源变得容易管理,从而使得代码更加优雅
你对AOP的理解
AOP,Aspect Oriented Programming 英文首字母缩写,意为面向切面编程,是Spring的核心思想之一
AOP是对OOP(面向对象编程)的一种补充,能够做到很多面向对象无法做到的事情,比如需要在所有方法执行前开启事务,打印日志,如果使用面向对象来编程,将会产生大量重复代码,而使用AOP,可以将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,一次解决这些问题。而这些重复的代码,一般统称为横切逻辑代码
使用AOP,在不改变原有业务逻辑的情况下,实现解耦合,避免横切逻辑代码重复
AOP的使用场景包括日志记录,性能统计,安全控制,事务处理,异常处理等等
它是基于动态代理实现的,分为JDK动态代理和CGLIB动态代理。JDK动态代理只支持实现了接口的类 ,CGLIB支持没有实现接口的类。Spring默认使用JDK动态代理,如果被代理类没有实现接口,会选择CGLIB动态代理
Spring的Bean懒加载和非懒加载有什么区别
懒加载:需要使用对象的时候才创建,节省资源,但不利于提前发现错误
非懒加载,也叫迫切加载,容器启动时就创建对象,消耗资源,但有利于提前发现错误
spring中默认时迫切加载,即在项目启动时,spring会扫描符合条件的所有bean并将其初始化
如果需要懒加载,可以使用@Lazy注释或者xml中配置属性default-lazy-init="true"
Spring的依赖注入方式有哪些
方式一:setter方式注入,通过反射调用无参构造方法生成对象,再通过对于的setter方法注入配置的值,支持注解和xml两种实现方式
方式二:构造器方式注入,通过反射调用有参构造方法生成对象,支持注解和xml两种实现方式
注解实现方式:@Autowired,它是默认按类型匹配的、@Resource,它是默认按名字匹配的
说一下定义切面相关的注解
@Aspect:定义切面
@Pointcut:定义切点 = cn.xx.service.*
@Before:前置通知,在目标方法运行之前运行
@After:后置通知,在目标方法运行结束之后运行(无论方法正常结束还是异常结束)
@AfterReturning:返回通知,在目标方法正常返回之后运行
@AfterThrowing:异常通知,在目标方法出现异常以后运行
@Around:动态代理,手动推进目标方法运行
Bean的四种注册方式
方式一:普通注册方式,直接通过class注册
方式二:简单静态工厂方式注册
方式三:简单实例工厂方式注册
方式四:FactoryBean方式注册
注册Bean的注解有哪些
@Controller/@RestController 一般用于定义控制层的类
@Service 一般用于定义服务层的类
@Repository 一般用于定义持久层类
@Component 定义一般类
@Configuration 定义配置类
IOC的启动流程有了解过吗
当Spring启动时,IOC容器会加载Spring的配置文件,包括XML配置或者注解,然后解析这些Bean并把相关定义信息封装成BeanDefinition对象,通过Bean注册器BeanDefinitionRegistry注册到IOC容器,也就是一个ConcurrentHashMap中
此时会找出所有的单例且非惰性加载的bean,根据其BeanDefinition进行Bean的实例化,它会判断如果bean中有方法覆盖,就使用JDK反射创建Bean,否则使用CGLIB方式生成代理。然后把实例化好的Bean缓存到一个ConcurrentHashMap中
Bean的生命周期讲一下
从宏观的角度来说就是:实例化 ,属性注入,初始化,使用,销毁。更细的生命周期如下
实例化:如果是单例且迫切加载的bean,在Spring容器启动时就会根据BeanDefinition进行实例化,如果时设置了懒加载或者多例模式的bean,在用的时候才会实例化
属性赋值:通过BeanDeifinition找到当前Bean所依赖的其他Bean,如果容器中有就直接拿过来,如果没有就根据创建流程区创建依赖的bean,然后通过反射给依赖的字段注入值
然后会调用BeanPostProcessor的前置处理器,对于@Autowired和@Transcational就是基于BeanPostProcessor来实现的。
接着会看Bean是否实现InitializingBean ,如果有会触发其afterPropertiesSet方法的调用
接着是调用我们自定义的bean的init-method方法,此时会调用执行
然后是调用BeanPostProcessor的后置处理
容器正常关闭,Bean进行销毁,会先调用实现了DisposableBean的destory方法。
接着调用我们指定的bean的destroy-method方法,此时会调用执行
单例多例的区别
单例和多例属于对象模式,单例模式指对象在整个系统中只存在一份,多例模式则可以有多个实例。
在spring的ioc容器中的bean默认都是单例的,如果需要使用多例,可以通过修改scope属性:scope="prototype"
如果一个bean是单例模式的,在处理多次请求的时候,在ioc容器中只实例化一个bean,这个对象会被保存在一个map中,当有请求来的时候,会先从map中查看,如果有就直接使用这个对象,没有才会实例化新的对象。
如果是多例(prototype)模式的bean,每次请求来的时候,会直接实例化新的bean,没有map缓存的过程。
Spring的Bean被指定为prototype以及singleton有什么区别
这两者分别指的是多例和单例模式,singleton即单例模式,指对象在整个系统中只存在一份;prototype即多例模式系统中可以有多个实例。
如果一个bean是单例模式的,在处理多次请求的时候,在ioc容器中只实例化一个bean,这个对象会被保存在一个map中,当有请求来的时候,会先从map中查看,如果有就直接使用这个对象,没有才会实例化新的对象。
如果是多例模式的bean,每次请求来的时候,会直接实例化新的bean,没有map缓存的过程。
在spring的ioc容器中的bean默认都是单例的,如果需要使用多例,可以指定scope属性:scope="prototype"
BeanFactory和ApplicationContext有什么区别
BeanFactory接口是IOC容器的核心接口,定义了管理bean的最基本方法,比如实例化,配置,管理,获取bean的方法
ApplicationContext接口是BeanFactory接口的子接口,除了继承BeanFactory中所有管理bean的方法,还拥有环境、国际化、资源、事件等服务相关的接口
BeanFactory是延迟加载,ApplicationContext是迫切加载
BeanFactory和FactoryBean的区别
BeanFactory接口是IOC容器的核心接口,定义了管理bean的最基本方法,比如实例化,配置,管理,获取bean的方法
FactoryBean是IOC容器创建bean的一种形式,可以通过实现此接口来创建实例化过程比较复杂的bean
IOC容器是如何保证Bean的单例的?
IOC容器会将单例模式的bean放入一个ConcurrentHashMap中,需要这个bean时直接到这个map中获取,如果没有找到才会实例化这个bean。而ConcurrentHashMap本身时线程安全的,也就保证了Bean是单例的
Spring如何解决Bean的循环依赖
循环依赖分为三种,构造器注入循环依赖 ,setter方式注入循环依赖,多例模式Bean的循环依赖。而Spring解决了单例bean的setter注入循环依赖
setter循环依赖的解决主要使用了三级缓存
- 一级缓存,用来缓存已经实例化好的bean,即单利Bean缓存池
- 二级缓存,用来缓存正在创建的bean
- 三级缓存,用来缓存创建bean的实例工厂ObjectFactory
假设有两个bean,A依赖B,B依赖A
当实例化好A,在属性注入环境,发现A依赖了B,会先将正在创建的A的实例工厂ObjectFactory放入三级缓存,然后去创建B的实例。
走Bean的实例化流程创建B,在B的属注入环节发现,B依赖了A,这个时候就会去三级缓存中,找到A的创建工厂ObjectFactory获取A的实例,并注入到B中。此时B就初始化好了,然后将B实例放入一级缓存。最后将B实例注入到A中,A也就创建好了
在getBean的时候,如果单利Bean缓存池没有Bean,就会走二级缓存尝试获取,如果也没有,就会走三级缓存拿到Bean的ObjectFacory创建Bean,然后把Bean放入二级缓存。
Spring构造器注入能循环依赖吗
构造注入不能解决循环依赖的原因是:如果A的构造其中依赖了B B的构造器中又依赖了A 在getSingleton中三级缓存需要调用getObject()构造器,来构造提早暴露但未设置属性的bean,此时就会产生无限递归创建
多例模式下Bean是不做缓存的,所以就没法暴露ObjectFactory,也就没办法解决循环依赖
说几个Spring的IOC的容器工厂类
BeanFactory:IOC容器顶层接口,提供了Bean获取的基础方法
DefaultListableBeanFactory:是整个 bean 加载的核心部分,Spring 注册及加载Bean 的默认实现
ApplicationContext:除了实现IOC基本功能外,还扩展了国际化支持,资源访问,事件发布
ClasspathXmlApplicationContext:从classpath中获取XML配置
你知道Spring的AOP主要基于什么设计模式实现吗
AOP的实现原理是基于动态代理,动态代理就是在运行时期动态的为原生类生成代理类以达到代码增强的目的,且代理类是持有原生类的,可以在代理类中调用原生类以及做一些增强业务。
动态代理分为JDK动态代理和CGLIB代理,CGLIB代理需要导入相关的jar包,两者的区别是JDK动态代理要求目标类需要实现至少一个接口。而CGLIB则是基于继承进行代理,原生类可以不实现任何接口
Spring中默认采用JDK动态代理,如果原生类没有实现任何接口,Spring会选择CGLIB代理,或者你可以在配置文件中强制指定使用CGLIB代理
你知道@Autowaire自动注入的实现原理吗?
自动注入是通过BeanPostProcessor 后置处理器AutowiredAnnotationBeanPostProcessor完成的,在Bean实例化过程中,触发了AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法的调用执行,它就会扫描当前类中是否有@Autowired注解,然后得到自动注入依赖的bean的类型,并去容器中得到依赖的bean实例,如果没有就走Bean的实例化流程创建依赖的Ban,然后反射进行字段赋值。
你知道@Transcational注解的实现原理吗?
分为两个动作把,第一个是解析@Transcational注解,在Sping中有个后置处理器InfrastructureAdvisorAutoProxyCreator,在Bean的初始化过程中,它负责解析标记了@Transcational注解的类,生成代理。还创建了 TransactionAttributeSource ,它是对事务注解的封装,以及 TransactionInterceptor 事务拦截器。
在执行业务方法的时候,代码会进入事务拦截器TransactionInterceptor去执行事务相关的代码,TransactionInterceptor主要是通过调用TranscationManagerment的事务API,而TranscationManagerment又是调用connection的事务API完成事务操作。