控制反转(IoC):就是创建对象的控制权,被反转到了Spring框架上。通常我们实例化一个对象时,都是使用类的构造方法来new一个对象,这个过程是由我们自己来控制的,而控制反转就把new对象的工交给了Spring容器。IoC的主要实现方式有两种:依赖查找、依赖注入。
依赖注入:IoC容器会把当前对象所需要的外部资源动态的注入到当前组件中。
Spring依赖注入的方式主要有四个,基于注解注入方式、set注入方式、构造器注入方式、静态工厂注入方式。推荐使用基于注解注入方式,配置较少,比较方便。
Spring IOC容器通过xml,注解等其它方式配置类及类之间的依赖关系,完成了对象的创建和依赖的管理注入。实现IOC的主要设计模式是工厂模式。
AOP主要一般应用于签名验签、参数校验、日志记录、事务控制、权限控制、性能统计、异常处理等, 实现AOP的主要设计模式就是动态代理。Spring的动态代理有两种:一是JDK的动态代理;另一个是cglib动态代理.
• 连接点(JoinPoint)需要在程序中插入横切关注点的点,连接点可能是在类初始化、方法调用、字段调用或处理异常等等。Spring中只支持方法执行连接点。
• 切入点(Pointcut)一组相关连接点的集合。
• 通知(Advice)在连接点上执行的行为,增强提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段。包括前置增强(before advice)、后置增强 (after advice)、环绕增强 (around advice)。
• 切面(Aspect)通知和切入点的结合。
• 织入(Weaving)是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程。
• 代理(Proxy)通过代理方式来对目标对象应用切面。AOP代理可以用JDK动态代理或CGLIB代理实现。
• 目标对象(Target)需要被织入关注点的对象。即被代理的对象。
Ioc是怎么设计的
第一条设计路径,从接BeaFactory --> HierarchicalBeanFaxtory --> ConfigurableBeanFactory是一条主要的BeanFactory设计路径。
BeanFactory定义了容器基本的功能,就好像水桶能装水一样。
HierarchicalBeanFaxtory增加了BeanFactory的方法,如增加了getParentBeanFactory()方法。
ConfigurableBeanFactory定义了一些BeanFactory的配置功能。
IoC容器的设计中,容器有两个系列,可以看成是容器的具体表现形式:
BeanFactory 简单容器:实现了容器的基本功能,典型方法如 getBean、containsBean、isSingleton;
ApplicationContext 应用上下文:在简单容器的基础上,增加上下文的特性。
为什么要设计两个系列,而不是一个?这就涉及到架构设计的模式了,底层定义核心流程,上层扩展功能实现,高内聚、低耦合。在架构设计中,这样的分层是很有必要的,可以随时替换掉一个抽象层。
二. 常用注解
@Component:标注一个普通的Spring Bean类。
@Controller:标注一个控制器组件类。
@Service:标注一个业务层组件类。
@Repository:标注一个dao持久层组件类。
@Autowired与@Resource都可以用来装配Bean,都可以写在字段、setter方法上。他们的区别是:@Autowired默认按类型进行自动装配(该注解属于Spring),默认情况下要求依赖对象必须存在,如果要允许为null,需设置required属性为false,例:@Autowired(required=false)。如果要使用名称进行装配,可以与@Qualifier注解一起使用。
@Resource默认按照名称进行装配(该注解属于J2EE),名称可以通过name属性来指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行装配;如果注解写在setter方法上,默认取属性名进行装配。当找不到与名称相匹配的Bean时,会按照类型进行装配。但是,name属性一旦指定,就只会按照名称进行装配。
SpringMVC常用注解
@Controller声明该类为SpringMVC中的Controller,控制器Controller 负责处理由DispatcherServlet分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。
@RequestMapping :作用是建立请求URL和处理方法之间的对应关系,各各参数作用如下:
path-指定请求路径的URL
value属性和path属性是一样的
mthod 指定该方法的请求方式
params 指定限制请求参数的条件
headers 发送的请求中必须包含的请求头
@ModelAttribute:
@SessionAttributes
@PathVariable
@requestParam
三.自定义注解怎么写,自定义注解上面再加注解,叫什么
元注解,注解注解的注解,给注解加的注解,在注解声明时,在上面加的注解
1、@Target 用来标记这个注解可以使用在X位置 这个位置由ElementType枚举的常量对象来指定。
2、@Retention(x) 作用:标记这个注解可以滞留到X阶段 这个生命周期由RetentionPolicy枚举的常量对象来指定。SOURCE(源代码),CLASS(字节码阶段),RUNTIME(运行时) 没有加默认的注解的周期就是源代码阶段。
3、@Documented 作用:标记这个注解是否可以被javadoc.exe读取到API中
4、@Inherited 作用:标记这个注解是否是可以被子类继承
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
定义注解格式: public @interface 注解名 {定义体}
注解参数的可支持数据类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型; 3.Class类型;4.enum类型;5.Annotation类型;
6.以上所有类型的数组
Annotation类型里面的参数该怎么设定:
第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号
四.spring请求流程
1. 请求离开浏览器时,会带有用户正在请求内容的信息。至少会带有被请求的URL。不过请求还可能带有其他信息,例如用户利用表格提交的信息。
2. 请求的第一个停止点是Spring的DispatcherServlet。和大多数Java的MVC框架一样,Spring将所有请求都经过一个前端Servlet控制器。这个控制器是一个常用的Web应用模式,一个单实例的servlet委托应用系统的其他模块进行真正的处理工作。在SpringMVC中,DispatcherServlet就是这个前端控制器。
3. DispatcherServlet的工作是将请求发送给Spring MVC控制器,所谓控制器就是一个处理请求的Spring组件。不过,一个典型的应用程序可能会有多个控制器,DispatcherServlet需要知道请求应该发送给哪个控制器。因此,DispatcherServlet会查询一个或多个控制器映射,了解请求的下一个停止点是什么。处理器映射会根据请求携带的URL做出决策。
4. 一旦DispatcherServlet找到了一个控制器对象,它会将请求以适当的方式派发给这个控制器。在控制器上,请求卸下其负载,并且等待控制器处理这些信息(实际上,一个设计良好的控制器自己只执行很少或者自己不执行处理工作,而是委托给一个或多个业务组件,让它们负责业务逻辑处理)。
5. 完成业务逻辑后,一般会生成一些需要返回给用户并在浏览器中显示的信息。这些信息被称为模型(model)。不过,仅仅向用户展示这些未加工的信息是不够的,这些信息需要被进行格式化,一般是HTML。对那些需要传递给视图的信息,一般是JSP。
6. 控制器做的最后一件工作,是将模型数据和视图的名称打包到ModelAndView对象中。接着,将带有新ModelAndView捆绑的请求发送回DispatcherServlet。顾名思义,ModelAndView不仅携带模型数据,还携带由哪个视图来呈现结果的提示。
7. 因此,控制器并不会和特定的视图耦合。ModelAndView并不携带具体JSP的引用,而是只携带视图对象的逻辑名,以便于查找生成结果HTML的实际视图。一旦ModelAndView被提交给DispatcherServlet,DispatcherServlet会要求视图解析器来协助查找实际的JSP。
8. 现在,DispatcherServlet已经知道由哪个视图来渲染结果,请求工作也差不多完成了。最后一个停止点是被提交的模型数据达到的视图实现(可能是一个JSP)。随着模型数据被提交给视图,请求的所有工作就完成了。视图会使用这些模型数据渲染一个页面,并通过响应对象返回给浏览器。
五. Spring用的设计模式
a) 工厂设计,使用工厂模式可以通过 BeanFactory或 ApplicationContext 创建 bean 对象。
两者对比: BeanFactory延迟注入(使用到某个 bean 的时候才会注入),相比于BeanFactory 来说会占用更少的内存,程序启动速度更快。ApplicationContext 容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。 ApplicationContext的三个实现类:
ClassPathXmlApplication:把上下文文件当成类路径资源。
FileSystemXmlApplication:从文件系统中的 XML 文件载入上下文定义信息。XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。
b) 单例模式, 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销. 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。
Spring 实现单例的方式:
xml :
注解:@Scope(value = "singleton")
c) 代理设计模式, AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理。
d) 模板方法, 模板方法模式是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的实现方式。jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。一般情况下,我们都是使用继承的方式来实现模板模式,但是 Spring 并没有使用这种方式,而是使用Callback 模式与模板方法模式配合,既达到了代码复用的效果,同时增加了灵活性。
包装器设计模式,我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式,Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式,Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
六. BeanFactory和ApplicationContext区别
BeanFactory:是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
ApplicationContext:应用上下文,继承BeanFactory接口,它是Spring的更高级的容器,提供了更多的有用的功能;1) 国际化(MessageSource)2) 访问资源,如URL和文件(ResourceLoader)3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层 4) 消息发送、响应机制(ApplicationEventPublisher)5) AOP(拦截器)
FileSystemXmlApplicationContext:从文件系统或者url指定的xml配置文件创建,参数为配置文件名或文件名数组
ClassPathXmlApplicationContext:从classpath的xml配置文件创建,可以从jar包中读取配置文件
WebApplicationContextUtils:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现
区别,两者装载bean:BeanFactory在启动的时候不会去实例化Bean,从容器中拿Bean的时候才会去实例化;ApplicationContext:ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;
选用:延迟实例化的优点:(BeanFactory)应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;
不延迟实例化的优点: (ApplicationContext)1.所有的Bean在启动的时候都加载,系统运行的速度快;2.在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题。3.建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)