文章目录
1. Servlet 生命周期
-
加载和实例化
当Servlet容器启动或客户端发送一个请求时,Servlet容器会查找内存中是否存在该Servlet实例,若存在,则直接读取该实例响应请求;如果不存在,就创建一个Servlet实例。 -
初始化
实例化后,Servlet容器将调用Servlet的init()方法进行初始化(一些准备工作或资源预加载工作)。 -
服务
初始化后,Servlet处于能响应请求的就绪状态。当接收到客户端请求时,调用service()的方法处理客户端请求,HttpServlet的service()方法会根据不同的请求 转调不同的doXxx()方法。 -
销毁
当Servlet容器关闭时,Servlet实例也随时销毁。其间,Servlet容器会调用Servlet 的destroy()方法去判断该Servlet是否应当被释放(或回收资源)。
2.介绍一下 nosql 和 redis
- nosql
-
nosql 是非关系型数据库。关系型数据库和非关系型数据库的一个显著区别是:关系型数据库中的数据存储在磁盘上,存取效率较低,但是安全;非关系型数据库中的数据是被存储在内存中的,存取效率高,但是一旦突然断电,数据就会丢失,所以不安全。
-
4种类型
列模型
就像关系型数据库是以一行作为一个记录,列模型数据库是以一列作为一个记录。键值对模型(key-value)
存储的数据是一个个“键值对”。文档存储模型
以一个个文档来存储数据,跟“键值对”类似。举例:MongoDB。图形数据模型
当实体之间的关系太过于复杂时,可以选择这个。
-
redis
Redis是一个开源的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。-
特点
(1)数据模型为key-value。
(2)可持久化。 我们知道,非关系型数据库因为其将数据存储在内存中的性质,极易造成数据 丢失。为了解决这个问题,Redis会自动将数据备份到硬盘中,当断点情况恢复后,能自动恢复数据。
(3)单线程工作模式,采用的是非阻塞I/O多路复用机制
(4)支持主从模式,所以能配置集群 -
为什么使用 redis ?
(1)针对不经常变动,且如果去数据库中查询会耗时久的热数据,我们可以放入缓存,这样,下次请求响应时就会快很多。有人说,Redis是最好的缓存数据库。
(2)在大并发的情况下,如果一时间很多请求同时访问数据库,会造成数据库瘫痪,解决办法是现在Redis中操作,等业务结束后(比如秒杀的东西被抢购完了),再将数据分批次存入数据库中。 -
redis 的使用
redis常用数据结构
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。-
Stirng
Strings 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字.
常用命令: set,get,decr,incr,mget 等。
应用场景:String是最常用的一种数据类型,普通的key/ value 存储都可以归为此类. -
Hash
常用命令:hget,hset,hgetall 等。
Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口 -
List
用命令:lpush,rpush,lpop,rpop,lrange等。
应用场景:
Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。
Lists 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用Lists结构,我们可以轻松地实现最新消息排行等功能。Lists的另一个应用就是消息队列,
可以利用Lists的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作Lists中某一段的api,你可以直接查询,删除Lists中某一段的元素。-
Set
常用命令:
sadd,spop,smembers,sunion 等。
应用场景:
Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
实现方式:
set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。 -
Sorted Set
常用命令:
zadd,zrange,zrem,zcard等
使用场景:
Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。
-
-
3. Spring
IOC 控制反转与 DI 依赖注入
- 什么是 IOC ?
IOC,是一种叫控制反转的编程思想。我把对象创建、管理的控制权都交给Spring容器,这是一种控制权的反转,所以Spring容器才能称为IOC容器。 - 为什么使用 IOC ?
复杂的应用程序类与类的协作关系往往是多边的,我们并不知道一个类功能的实现会依赖多少个另类对象来协作,所以在类中自行创建对象并且管理对象的整个生命周期,会造成代码的高度耦合以及不可想象的复杂度。如果我们能将对象的生命周期交给第三方组件来管理,当某个类需要另外的对象时第三方组件就直接创建出来交给它,这样,类就可以只专注于自己功能的实现,而不用去管理其他类对象的生命周期,这样类的功能就单纯了很多。
Spring(容器)就是这个第三方组件。我们只需要告诉Spring(容器)有哪些对象需要管理就行了,不用去关心Spring框架是如何创建对象的。这样,当某个类A需要类B对象时,如果类B已经声明交给了Sping容器管理,那么在程序运行到类A需要类B时,Spring容器就通过依赖注入的方式,将类B对象注入到类A中协助完成业务功能。
至于为什么要依赖注入,上文已经说得很明白了,就是为了减少代码中组件之间的耦合度。
Spring 容器和应用上下文
- Spring生产对象的地方我们就不叫工厂了,而叫做容器。容器是 Spring 框架实现功能的核心,容器不只是帮我们创建了对象那么简单,它负责了对象整个的生命周期的管理——创建、装配、销毁。
- 实际上,容器里面什么都没有,决定容器里面放什么对象的是我们自己,决定对象之间的依赖关系的,也是我们自己,容器只是给我们提供一个管理对象的空间而已。那么,我们怎么向容器中放入我们需要容器代为管理的对象呢?这就涉及到Spring的应用上下文了。
- 什么是应用上下文呢,你可以简单的理解成就是将你需要Spring帮你管理的对象放入容器的那么一种。应用上下文即是Spring容器的一种抽象化表述。Spring也为我们提供了多种类型的容器实现,供我们在不同的应用场景选择——
① AnnotationConfigApplicationContext:从一个或多个基于java的配置类中加载上下文定义,适用于java注解的方式;
② ClassPathXmlApplicationContext:从类路径下的一个或多个xml配置文件中加载上下文定义,适用于xml配置的方式;
③ FileSystemXmlApplicationContext:从文件系统下的一个或多个xml配置文件中加载上下文定义,也就是说系统盘符中加载xml配置文件;
④ AnnotationConfigWebApplicationContext:专门为web应用准备的,适用于注解方式;
⑤ XmlWebApplicationContext:从web应用下的一个或多个xml配置文件加载上下文定义,适用于xml配置方式。 - 总之你要将需要管理的对象(Spring中我们都称之问bean)、bean之间的协作关系配置好,然后利用应用上下文对象加载进我们的Spring容器,容器就能为你的程序提供你想要的对象管理服务了。
- 通过应用上下文将配置加载到IOC容器,让Spring替我们管理对象,待我们需要使用对象的时候,再从容器中获取bean就ok了:
public class Test {
public static void main(String[] args) {
//加载项目中的spring配置文件到容器
//ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");
//加载系统盘中的配置文件到容器
ApplicationContext context = new FileSystemXmlApplicationContext("E:/Spring/applicationContext.xml");
//从容器中获取对象实例
Man man = context.getBean(Man.class);
man.driveCar();
}
}
自动化装配 bean
自动化装配 bean
我们把Spring创建应用对象之间的协作关系的行为成为装配。
AOP 切面编程
-
为啥要使用这样一种编程思想和相关的AOP技术?
就是为了业务模块间的解耦,尤其在现代的软件设计中强调高内聚、低耦合,要求我们的业务模块化,各个功能模块只关注自己的逻辑实现,而不用关注与主业务逻辑不相关的功能。然而,在面向对象的系统设计中,系统中不可或缺的一些功能如日志、事务是散布在应用各处与主逻辑代码高度耦合的,这让主业务代码变得相当冗余、难以复用。而在面向切面的编程思想中,我们是考虑将那些散布在应用多处的重复性代码抽离出来封装成模块化的功能类,一来让主业务逻辑更加专注、简单,二来模块化的日志、事务也便于复用和移植,这就是解耦的思想。但是,解耦并不等于断耦,抽离的功能最终还是要以某种方式"还"(qie)回去,否则应用的功能就不完善了。这里,“还”(qie)回去的技术就是AOP技术,而这种解耦的编程思想就是AOP的编程思想。 -
核心概念
(1)横切关注点
如上描述,我们把日志、事务、权限等代码重复性极高却散布在应用程序各个地方的功能称为横切关注点。(2)连接点(Join Point)
可以被拦截到的点。增删改查的方法都可以被增强,这些方法就可以被称为连接点。(3)通知/增强(Advice)【方法层面的增强】
现在对save方法进行权限校验,权限校验的方法我们叫做通知,或增强。(4)切入点(Pointcut)
真正被拦截到的点。在实际开发中,我们只对 save 方法进行了方法增强, save 被称为切入点。(5)切面(Aspect)
多个通知和多个切入点的一个组合。切面类中写的是增强方法。(6)Target
被增强的对象。对UserDao增强,UserDao称为目标。(7)织入(Weaving)
将通知(Advice)应用到目标(Target)的过程。将权限校验的方法的代码应用到UserDao的save方法的过程。(8)Proxy
代理对象。当我们对目标对象进行了织入以后产生的一个代理类。 -
Spring 中的通知类型
(1)前置通知【@Before】
在目标方法执行之前进行操作。可以获得切入点的信息。
(2)后置通知【@After】
在目标方法执行之后进行操作。可以获得方法的返回值。
(3)环绕通知【@Around】
在目标方法执行之前和之后进行操作。可以阻止目标方法的执行。
(4)异常抛出通知【@AfterThrowing】
在程序出现异常的时候进行通知。可以获得异常信息。
(5)最终通知
无论代码是否异常,总会执行。
BeanFactory 和 ApplicationContext是什么关系,使用有什么区别?
-
BeanFactory 是 Spring 里面最底层的接口,提供了最简单的容器功能,只提供了实例化对象的取对象的功能。
-
ApplicationContext:
应用上下文,继承了 BeanFactory 接口,它是 Spring 的一种更加高级的容器,提供了更多有用的功能。
(1)国际化(MessageSource)
(2)访问资源,如URL和文件(ResourceLoader)
(3)载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
(4)消息发送、响应机制(ApplicationEventPublisher)
(5)AOP(拦截器) -
两者装载bean的区别
(1)BeanFactory:
BeanFactory在启动的时候不会去实例化Bean,只有从容器中拿Bean的时候才会去实例化;
(2)ApplicationContext:
ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化; -
我们该用 BeanFactory 还是 ApplicationContent ?
延迟实例化的优点:(BeanFactory)
应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势。不延迟实例化的优点: (ApplicationContext)
(1)所有的Bean在启动的时候都加载,系统运行的速度快;
(2) 在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题
(3)建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成) -
Spring事件机制(订阅发布模式 == 观察者模式)
ApplicationContext事件机制是观察者设计模式的 实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。 如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发。
两个重要成员
ApplicationEvent:容器事件,必须由ApplicationContext发布;
ApplicationListener:监听器,可由容器中的任何监听器Bean担任。
注解开发
-
Spring @Component 注释是一个类型级的注释,它能标识表示一 Spring bean (也称 Spring 组件)的类。
-
建议使用 @Component 注释的特殊形式来注释应用程序的控制器、服务和数据访问对象 (DAO )。例如,使用@Controller 注释控制器、使用@Service 注释服务以及使用@Repository 注释 DAO。
-
@Service 注解的使用:
像@Service 注释一样,@Component、@Repository、 @Controller 注释通过 value 特性指定 bean 名称。如果不指定 bean 的名称,则Spring 假定 bean 名称与以小写字母开头的类的名称相同。 -
如果启用 Spring 类路径扫描功能,则使用@Component、@Controller 、@Service 或@Repository 注释 bean 类将 自动注册到 Spring 容器。
@Autowired 通过类型自动装配依赖项
@Autowired 注释用于通过类型“自动装配依赖项”。@Autowired 注释可以在造函数级、方法级和字段级使用。