Spring框架简介
Spring是一个一站式的框架,提供了表现层(springMVC)到业务层(Spring)再到数据层(Springdata)的全套解决方案;Spring的两大核心Ioc(控制反转)和AOP(面向切面编程)更是给我们的程序解耦和代码的简介提供了支持。
AOP与IOC
(1)AOP与IOC给spring的业务层提供支持,使程序的耦合度更低,代码更简洁
(2)AOP原理:既面向切面编程,就是提取公共部分,集中解决一些公共问题
(3)IOC原理:控制反转。在传统过程中,当某一个对象依赖于另外一个对象时,会由该对象去创建另外一个对象,有了ioc后,将创建过程交给IOC,由spring创建bean,从而只需给该对象注入即可。
控制反转和依赖注入的理解
详情地址:https://blog.csdn.net/sinat_21843047/article/details/80297951
- Ioc是什么:即“控制反转”,是一种设计思想。意味着将你设计的对象交给容器控制,而不是传统的在你的对象内部直接控制。传统的JavaSE设计,我们是直接通过new来创建对象,由程序主动去创建对象,也就是正转;而现在是通过Ioc容器来控制对象的创建,因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;
- Ioc能做什么:Ioc对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。很好的体现了面向对象设计法则之一——好莱坞法则:“别找我们,我们找你”,即由Ioc容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
- DI即“依赖注入”,由容器动态的将某个依赖关系注入到组件中,依赖注入的目的并非为软件系统带来更多的功能,而是为了提升组件重用的效率,并为系统搭建一个灵活、可拓展的平台。
- 深入分析:
谁依赖于谁:当然是应用程序依赖于IoC容器;
为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。 - Ioc和DI是什么关系?
属于同一个概念的不同角度的描述。由于控制反转概念比较含糊(可能只是理解为容器控制对象这一层面,很难让人想到谁来维护对象关系),相对于Ioc而言,“依赖注入”明确描述了“被注入对象依赖Ioc容器配置依赖对象”。 - Spring的核心:所谓Ioc,对于Spring框架来说,就是由Spring来负责控制对象的生命周期和对象间的关系。
- Spring所倡导的开发方式就是如此,所有的类都会在Spring容器中登记,告诉Spring你是个什么东西,你需要什么东西,然后Spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要您的东西。所有的类的创建、销毁都由Spring来控制,也就是说控制对象生命周期的不再是引用它的对象,而是Spring.对于某个具体对象而言,以前是它控制其他对象,现在是所有对象都被Spring控制,所以这叫控制反转。
- DI(依赖注入):Ioc的一个重点是在系统运行中,动态的向某个对象提供他所需要的其他对象。这一点是通过DI来实现的。
- 反射,它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,Spring就是通过反射来实现注入的。
关于Spring AOP
AOP:AOP的出现确实解决外围业务代码和核心业务代码分离的问题,但它并不会替代OOP,如果说OOP的出现是把编码问题进行模块化,那么AOP就是把涉及到众多模块的某一类问题进行统一管理,因此在实际开发中AOP和OOP同时存在并不奇怪。
如何使用Spring AOP
可以通过配置文件或者编程的方式来使用Spring AOP。
配置可以通过xml文件来进行,大概有四种方式:
配置ProxyFactoryBean,显式地设置advisors, advice, target等
配置AutoProxyCreator,这种方式下,还是如以前一样使用定义的bean,但是从容器中获得的其实已经是代理对象
通过< aop:config>来配置
通过< aop: aspectj-autoproxy>来配置,使用AspectJ的注解来标识通知及切入点
Spring的优势
- 方便解耦,简化开发:控制反转将对象的创建交给了spring,简化了开发,降低了代码之间的耦合性和侵入性。
- 声明式事务的支持:方便对程序进行声明式事物管理,只需通过配置就可以完成对事物管理。提高开发效率和质量。
- 方便集成各种优秀框架:降低各种框架的使用难度,其内部提供了对各种优秀框架如(struts2,hibernate,mybatis,quartz,jpa)等的直接支持。
- 方便程序的测试:可以用非容器方式进行几乎所有的测试工作,使测试工作不再昂贵,而是随手可测。
- 降低javaEE API的使用难度:JDBC,Javamail,远程调用等,spring对它们进行了封装,使这些API的使用难度大大降低。
JavaBean的含义
JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属性。名称中的“Bean”是用于Java的可重用软件组件的惯用叫法。
总结:
- 所有属性必须为private
- 提供默认构造方法
- 提供getter和setter,必须给私有属性提供公开的方法以供外部调用。
- 实现serializable接口
补充:servlet的本质其实也是一个java bean,controller是对servlet的封装,底层依旧是servlet。
Bean的作用域
1. Spring提供了4种作用域:singleton(单例) prototype(原型) Session(会话) request(请求)
2. XML中的bean中有属性:scope ,默认是单例,可以设置为原型。会话和请求的作用域需要在web.xml中配置
3. 注解中有注解@Scope(“singleton”),@Scope(“prototype”),默认是单例,可以设置为原型。
单例模式
一中常见的软件设计模式,该模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
为何使用:该模式主要解决一个全局使用的类频繁的创建和销毁,当你想控制实例数目和节省系统资源的时候可以使用。
单例模式的实现方式:
- 懒汉式:优点是第一次调用才初始化,避免内存浪费,缺点是必须加锁才能保证单例,影响效率。
- 饿汉式:没有加锁,执行效率会提高,但是类加载时就初始化,浪费内存。
- 双检锁:实现难度复杂,采用双锁机制,安全且多线程情况下能保持高性能。
- 枚举:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
懒加载与非懒加载的优缺点:
懒加载:对象使用的时候才去创建,节省资源,但是不利于提前发现错误。
非懒加载:容器启动的时候立刻创建对象。消耗资源。利于提前发现错误。
当scope=“prototype” (多例)时,默认以懒加载的方式产生对象。
当scope=“singleton” (单例)时,默认以非懒加载的方式产生对象。
Spring优化配置
- 在Spring中,bean的依赖注入有两种方法,第一种使用xml配置,第二种使用annotation注解配置。
在applicationContext.xml中配置< context:annotation-config/>来启用。- @Resource注解可以标注在属性和方法上。默认按照对象名称注入属性值,其次是按类型。
- @Autowired注解按照类型注入,默认情况下他要求依赖的对象必须存在,如果允许为null,可以设置它的required属性为false.
- @Qualifier,如果@Autowired想使用对象名称注入,可结合@Qualifier注解确定注入的对象名称。
- 启用组件扫描:< context:component-scan base-package=”cn.itlaobing.jdbc”/>
常用组件:
@Service:用于在业务类上
@Controller:用于配置在控制器上,表明该类可以接收请求并进行响应
@Respository:用于配置在数据访问组件上
@Component:用于配置在以上三种组件之外的组件上
@Scope:可设置bean的作用域
@Responsebody: 注解表示该方法的返回的结果直接写入 HTTP 响应正文 (ResponseBody)中,一般在异步获取数据时使用,通常是在使@RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。
@Autowired:自动注入,注入方式为byType
@Qualifier:Autowired默认是用byType类型注入,如果出现相同类型,则要搭配此注解使用
作用:
@Responsebody注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:
返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
两种方法对比:
< context:annotation-config/>只负责属性的注入
< context:component-scan base-package=”cn.itlaobing.jdbc”/>负责组件扫描和属性注入。只启用它就包括了< context:annotation-config/>的功能
- Java-based:实现免xml的开发体验
@Bean注解用于标注在方法上,相当于xml文件中的,通常和@Configuration一起使用。
@Configuration:用于标注在类上,表示该类是一个配置类,相当于一个xml配置文件。
@ImportResource注解标注在类上,表示该类导入的外部资源。
Annotation和xml各自作为配置项的优点与缺点。
一、Annotation 的优点
1、保存在 class 文件中,降低维护成本。
2、无需工具支持,无需解析。
3、编译期即可验证正确性,查错变得容易。
4、提升开发效率。
Annotation 缺点:
1、若要对配置项进行修改,不得不修改 Java 文件,重新编译打包应用。
2、配置项编码在 Java 文件中,可扩展性差。
二、XML
目前web应用中几乎都使用xml作为配置项,例如我们常用的框架Struts、Spring、Hibernate、IBatis等等都采用xml作为配置。
XML优点:
1. xml作为可扩展标记语言最大的优势在于开发者能够为软件量身定制适用的标记,使代码更加通俗易懂。
2. 利用xml配置能使软件更具扩展性。
3. 具有成熟的验证机制确保程序正确性,避免非法的配置导致应用程序出错。
4. 修改配置而无需变动现有程序。
XML缺点:
- 需要解析工具或类库的支持。
- 解析xml占用系统资源。
- 配置文件过多导致管理变得困难。
- 开发效率低下。
- 查错变得困难。往往配置的一个手误导致莫名其妙的错误。
- 配置项与代码间存在潜规则。改变了任何一方都有可能影响另外一方。
Spring测试:
传统的单元测试都是使用Junit测试框架下进行的,Spring的单元测试也可以在junit框架下进行,但存在一些问题:
一、使用Junit对spring进行单元测试缺点:
- 性能开销大
- 不应该由测试代码管理spring容器,应该反过来。
- 无法独立于服务器完成事务测试。
二、使用Spring Test进行单元测试优点:
- 减少开销
- 可以直接使用@AutoWired注入spring容器或Bean
- 支持事务测试,集成测试等。
Spring AOP:
AOP定义:AOP是OOP的延续,称为面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP与OOP:
- OOP实际是对对象的属性和行为进行抽象封装
- AOP则只是处理某个步骤和阶段的时候,从中进行切面的提取,如权限判断、日志记录
@Aspect:定义切面,用于标注类(切面类),类中包含@Pointcut和Advice(通知)方法
@Pointcut:定义切入点
AOP主要功能
日志记录,性能统计,安全控制,事务处理,异常处理等等wn及扩展
AOP主要意图
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码
代理(Proxy)
AOP是通过代理实现的在不改变原有代码的前提下,实现增强业务功能。
代理模式有多种:静态代理、JDK动态代理、CGLib代理等。Spring AOP使用的是CGLib代理。
Spring支持事务类型:编程式事务和声明式事务
编程式事务是在代码中在代码中显式调用开启事务、提交事务、回滚事务的相关方法,与业务的耦合度高,难以复用
声明式事务:本质使用AOP,将业务和事务管理分离,降低耦合度和提高事务的复用能力。声明式事务可以通过注解和配置来管理事务,操作简单。
事务的特性:
原子性:表明事务是不可再分的,即要么都执行,要么都不执行。
一致性:表明事务在执行前后数据处于一致的状态。
隔离性:表明一个事物的执行,不受其他事物的影响,即并发执行的事务互不干扰。
持久性:表明事务的执行对数据的更改是永久的。
Spring声明式事务的提交行为:
Spring的声明式事务是AOP的一种应用,将@Transactional注解标注在业务上,表示告诉Spring容器,该方法调用前要打开事务,方法调用结束后提交或回滚事务。
在企业级应用中,多用户访问数据库是常见的场景,这就是所谓的事务的并发。事务并发所可能存在的问题:
- 脏读:一个事务读到另一个事务未提交的更新数据。
- 不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。
- 幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
- 丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
注解与反射
1.注解定义:是一种元数据,代码级别的注释。
元数据(MetaData):即定义数据的数据.比如,我们要搜索一首歌(歌本身就是数据),可以通过歌名,歌手,专辑等信息来搜索,这些歌名,歌手,专辑就是这首歌的元数据.因此数据库的元数据就是一些注明数据库信息的数据。
2.注解的作用:
- 编写文档: 通过代码里标识的注解生成文档. [ 例: 生成doc文档 ]
- 代码分析: 对代码进行分析. [ 例: 注解的反射 ]
- 编译检查: 让编译器能够实现基本的编译检查. [ 例: Override ]
3.反射定义:在运行期间,动态的去获取类中的信息(类的信息,方法信息,构造器信息,字段等信息)。
创建对象可以通过new运算符硬编码方式创建对象,也可以通过反射机制在运行时动态的创建对象。