目录
一、Spring 概述
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
- Spring是一个开源免费的框架 , 容器 .
- Spring是一个轻量级的框架 , 非侵入式的 .
- 控制反转 IoC , 面向切面 Aop
- 对事物的支持 , 对框架的支持
Spring模块功能:
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory ,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
二、IOC
1、IOC本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.
对象由Spring 来创建 , 管理 , 装配。2、IOC创建对象方式
(1)通过无参构造方法来创建
<bean id="user" class="com.kuang.pojo.User"> <property name="name" value="kuangshen"/> </bean>
(2)通过有参构造方法来创建
<!-- 第一种根据index参数下标设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <!-- index指构造方法 , 下标从0开始 --> <constructor-arg index="0" value="kuangshen2"/> </bean> <!-- 第二种根据参数名字设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <!-- name指参数名 --> <constructor-arg name="name" value="kuangshen2"/> </bean> <!-- 第三种根据参数类型设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <constructor-arg type="java.lang.String" value="kuangshen2"/> </bean>
3、依赖注入(DI)
(1)构造器注入
(2)set注入
必须有set方法 , 方法名set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is
- 常量注入
<property name="name" value="小明"/>
- bean注入
<property name="address" ref="addr"/>
- 数组注入
<property name="books"> <array> <value>西游记</value> <value>红楼梦</value> <value>水浒传</value> </array> </property>
- List注入
<property name="hobbys"> <list> <value>听歌</value> <value>看电影</value> <value>爬山</value> </list> </property>
- Map注入
<property name="card"> <map> <entry key="中国邮政" value="456456456465456"/> <entry key="建设" value="1456682255511"/> </map> </property>
- Set注入
<property name="games"> <set> <value>LOL</value> <value>BOB</value> <value>COC</value> </set> </property>
- Null注入
<property name="wife"><null/></property>
- Properties注入
<property name="info"> <props> <prop key="学号">20190604</prop> <prop key="性别">男</prop> <prop key="姓名">小明</prop> </props> </property>
(3)拓展注入
- p命名空间注入:set方法注入
<bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
- c命名空间注入:构造器注入
<bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>
三、Spring配置
1、alias别名
<!--设置别名:在获取Bean的时候可以使用别名获取--> <alias name="userT" alias="userNew"/>
2、bean的配置
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello"> <property name="name" value="Spring"/> </bean>
3、协作导包
<import resource="{path}/beans.xml"/>
4、bean的作用域
singleton:单例模式,getBean创建实例相同
prototype:以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例5、bean的自动装配
- 自动装配是使用spring满足bean依赖的一种方法
- spring会在应用上下文中为某个bean寻找其依赖的bean。
- Spring中bean有三种装配机制,分别是:
1. 在xml中显式配置;
2. 在java中显式配置;
3. 隐式的bean发现机制和自动装配。- Spring的自动装配需要从两个角度来实现,或者说是两个操作:
1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;6、byName和byType
byName:
- 将查找其类中所有的set方法名,如setCat,获得去掉set且首字母小写字符串,即cat。
- 去spring容器中寻找是否有此字符串名称id的对象。
- 如果有,就取出注入;如果没有,就报空指针异常。
<bean id="user" class="com.kuang.pojo.User" autowire="byName"> <property name="str" value="qinjiang"/> </bean>
byType:
- 使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
7、注解@Autowired和@Qualifier、@Resource
@Autowired是byType自动装配的,不支持id匹配。需要导入 spring-aop的包!
@Qualifier 采用byName,不能单独使用
@Resource先进行byName查找,失败;再进行byType查找
@Autowired与@Resource异同:
1. @Autowired与@Resource都可以用来装配bean。都可以写在字段上,或setter方法上。
2. @Autowired默认按byType装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
3. @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
四、注解开发
1、配置文件
<!--指定注解扫描包--> <context:component-scan base-package="com.kuang.pojo"/>
作用:
- 进行注解驱动注册,从而使注解生效
- 激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
- 如果不扫描包,就需要手动配置bean
- 如果不加注解驱动,则注入的值为null!
2、pojo类添加注解 :@Component
3、属性注入: @value (变量定义或set方法上)
4、衍生注解:
- @Controller:web层
- @Service:service层
- @Repository:dao层
5、自动装配注解:@Autowired和@Qualifier、@Resource
6、作用域:@scope
singleton:默认,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收7、总结:
- XML与注解比较
XML可以适用任何场景 ,结构清晰,维护方便
注解不是自己提供的类使用不了,开发简单方便- xml与注解整合开发 :推荐最佳实践
xml管理Bean
注解完成属性注入
使用过程中, 可以不用扫描,扫描是为了类上的注解8、基于Java类进行配置:配置类@Configuration
五、代理模式
1、静态代理和动态代理
(1)静态代理角色分析
- 抽象角色 : 一般使用接口或者抽象类来实现
- 真实角色 : 被代理的角色
- 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
- 客户 : 使用代理角色来进行一些操作
(2)静态代理优点:
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- 公共的业务由代理来完成 . 实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
静态代理缺点 :
- 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低
(3)动态代理
- 动态代理的角色和静态代理的一样 .
- 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
- 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
基于接口的动态代理----JDK动态代理
基于类的动态代理--cglib
现在用的比较多的是 javasist 来生成动态代理 .核心 : InvocationHandler 和 Proxy
(4)基于接口的动态代理:-JDK动态代理
- JDK动态代理不要求代理类和委托类实现同一个接口,但是委托类需要实现接口,代理类需要实现InvocationHandler接口。
- 动态代理要求代理类InvocationHandler接口,通过反射代理方法(重写invoke方法),比较消耗系统性能,但可以减少代理类的数量,使用更灵活。
(5)基于类的动态代理:cglib提供的Enhancer
final BuyImpl car=new BuyImpl(); BuyCar proxy= (Buy)Enhancer.create(car.getClass(), new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy,methodProxy) throws Throwable { System.out.println("准备工作~~~"); Object result = method.invoke(car, args); System.out.println("后续工作~~~"); return result; } }); proxy.buyCar();
(6)动态代理的好处
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- 公共的业务由代理来完成 . 实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
- 一个动态代理 , 一般代理某一类业务
- 一个动态代理可以代理多个类,代理的是接口!
六、AOP
1、什么是aop?
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
2、Aop在Spring中的作用
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
方式一:spring API
编写接口XXXAdvice的实现类,重写对应方法
在spring配置文件中导入约束,并注册绑定<!--aop的配置--> <aop:config> <!--切入点 expression:表达式匹配要执行的方法--> <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/> <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config>
方式二:自定义类
编写一个切入类
在spring配置文件中导入约束,并注册绑定<!--aop的配置--> <aop:config> <!--第二种方式:使用AOP的标签实现--> <aop:aspect ref="diy"> <aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/> <aop:before pointcut-ref="diyPonitcut" method="before"/> <aop:after pointcut-ref="diyPonitcut" method="after"/> </aop:aspect> </aop:config>
方式三:注解实现
- 切面类:@Aspect
- 通知:@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")- 在Spring配置文件中,注册bean,并增加支持注解的配置
<!--第三种方式:注解实现--> <bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/> <aop:aspectj-autoproxy/>
七、整合MyBatis
八、事务管理
- 编程式事务管理
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码- 声明式事务管理
一般情况下比编程式事务好用。
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。- 为什么需要配置事务?
如果不配置,就需要我们手动提交控制事务;
事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!