Spring简介
- Spring:轻量级框架, Java EE的春天,当前主流框架。
- Spring是面向Bean的编程。
- Spring是一个容器框架,是一个大工厂。
- Spring中包含了两个最主要的组件IOC/DI和AOP。
- Spring对常用的框架做到了很好的管理支持。例如struts2、mybatis。
- Spring自身也推出了MVC框架(Spring MVC) 和 ORM框架(JDBC Template)。
优点
- 低侵入式设计
- 独立于各种应用服务器
- 依赖注入特性将组件关系透明化,降低了耦合度
- 面向切面编程特性允许将通用任务进行集中式处理
- 与第三方框架的良好整合
工厂设计模式
- 解释:将对象的创建交给工厂类(BeanFactory)完成。
- 作用:将对象与对象之间进行解耦合,减少程序中对象的零散创建,方便后期项目维护。
搭建Spring开发环境
- 导入jar包(通过idea创建spring项目默认会导入spring的jar包依赖)
- 添加xml配置文件,并且编写内容
- 头部部分会根据下边的标签自动生成、无需记录。
- 编写测试类
小结:了解工厂模式,spring是通过工厂模式创建对象;在工厂中解析配置文件,通过反射的方式创建对象,当我们需要使用对象的时候直接从工厂中获取。
工厂模式 = 配置文件 + 反射 + 工厂类
控制反转:对象的创建,以及给属性赋值的过程全部交给了Spring工厂完成。
依赖注入:给属性赋值
给属性赋值
设值注入
- 属性的类型是基本类型或是String类型
<!--
bean:代表一个对象。
id:是该bean的唯一标识。
class:类的路径
-->
<bean id="hellor" class="com.kgc.entity.Hellor">
<!--为类中的属性进行赋值:依赖注入-->
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
- 属性是自定义对象类型
<!--ref是reference单词的简写 意思是引用,引用的是对应属性(自定义对象类型)bean标签的id-->
<bean id="print" class="com.kgc.test.Printer">
<property name="cartridge" ref="color"></property>
</bean>
- 数组或者集合
<bean id="list" class="com.kgc.entity.Hellor">
<!--list类型属性赋值-->
<property name="hellorlist">
<list>抽烟</list>
<list>喝酒</list>
<list>烫头</list>
</property>
<!--set类型属赋值-->
<property name="hellorset">
<set>抽烟</set>
<set>喝酒</set>
<set>烫头</set>
</property>
<!--map类型属性赋值-->
<property name="hellormap">
<map>
<entry key="username" value="张三"></entry>
<entry key="pwd" value="123"></entry>
</map>
</property>
<!--给Properties类型的属性赋值,键和值只能是字符串-->
<property name="ss">
<props>
<prop key="a">张三</prop>
<prop key="b">李四</prop>
</props>
</property>
</bean>
构造注入(通过有参的构造方法为属性赋值)
<bean id="pro" class="com.kgc.entity.Hellor">
<!--index指定第几个参数,默认从0开始-->
<constructor-arg index="0" value="1001"></constructor-arg>
<constructor-arg index="1" value="张三"></constructor-arg>
<constructor-arg index="2" value="123"></constructor-arg>
</bean>
使用p命名空间注入属性值
- p 命名空间的特点:使用属性而不是子元素的形式配置Bean的属性,从而简化了配置代码
- 语法:
- 基本数据类型和字符串:p:属性名=“属性值”
- 对于引用Bean的属性:p:属性名-ref=“Bean的id”
- 用法:
- 使用前要先要在Spring配置文件中引入p命名空间
xmlns:p="http://www.springframework.org/schema/p"
- 使用p命名空间注入属性值
user类的属性。get/set省略
- 使用前要先要在Spring配置文件中引入p命名空间
public class User {
private String name;
private String pwd;
private Hellor hellor;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<bean id="user" class="com.kgc.entity.User" p:name="张三" p:pwd="123" p:hellor-ref="hellor">
</bean>
注入不同数据类型
Spring创建对象的次数
- bean标签有一个属性叫做 scope.
- 如果scope=”singleton”时,该对象只会被创建一次 (默认值)
- 如果scope=”prototype”时,该对象每次使用都会创建一个新对象
<bean id="hellor" class="com.kgc.entity.Hellor" scope="singleton">
<!--为类中的属性进行赋值:依赖注入(后边详细体现)-->
<property name="str" value="mi:三天不打***手就痒痒"></property>
</bean>
Spring中对象的声明周期
- 创建
- 如果scope=”singleton”时,工厂启动(new ClassPathXmlApplicationContext(“xx.xml”)) 就会创建该对象,该对象只会被创建一次(默认状态)。
- 如果 scope=”prototype”时, 每次使用的时候(ac.getBean(“id”))才会创建对象,当对象被创建的时候,会自动调用bean标签中init-method属性指定的方法,每次使用都会创建一个新对象。
- 销毁
- 调用工厂对象的close()方法的时候,对象被销毁,当对象被销毁之前,会自动调用bean标签中destroy-method属性指定的方法。
- 注意:至于scope=”singleton”时,工厂才会 销毁对象,并且先会调用myDestroy方法。
特殊对象的创建
-
什么是特殊对象(复杂对象) ?
- 没有构造方法或不能直接new的方式创建的对象。例如:Connection SqlSession SqlSqlSessionFactory对象
-
需求:将Conection的创建交给spring工厂来管理
-
步骤:
- 创建一个类 ConnectionFactoryBean 实现 FactoryBean 接口
- 实现接口中方法
getObject() 作用:获取对象
getObjectType() 作用:获取对象的类型
isSingleton() 作用:是否为单例 - 将ConnectionFactoryBean类配置到applicationContext.xml中
- 创建spring工厂,获取connection对象.
-
补充:BeanFactory和FactoryBean的区别? (面试题)
- 这两个没有太大的关系
- BeanFactory: 对象工厂
- FactoryBean: 是spring中一个接口,帮助我们创建特殊(复杂)对象,例如Connection
面向切面编程(AOP)
AOP原理:
- 将复杂的需求分解出不同方面,将散布在系统中的公共功能集中解决。
- 采用代理机制组装起来运行,在不改变原程序的基础上对代码段进行增强处理,增加新的功能。
- 在项目中寻找切入点,增加额外功能,但是又不影响目标类中的代码,使代码的通用性更强。(可以理解为方法拦截器)
AOP相关术语
-
增强处理(Advice):定义了切面是什么以及何时使用,描述了切面要完成的工作和何时需要执行这个工作。是织入到目标类连接点上的一段程序代码。增强包含了用于添加到目标连接点上的一段执行逻辑,又包含了用于定位连接点的方位信息。(所以spring提供的增强接口都是带方位名:BeforeAdvice、(表示方法调用前的位置)AfterReturninAdvice、(表示访问返回后的位置)ThrowAdvice等等,所以只有结合切点和增强两者一起才能确定特定的连接点并实施增强逻辑)
- 前置增强
- 后置增强
- 环绕增强、异常抛出增强、最终增强等类型
-
切入点(Pointcut):Advice定义了切面要发生“故事”和时间,那么切入点就定义了“故事”发生的地点。例如某个类或者方法名,Spring中允许我们使用正则来指定。
-
连接点(Join Point):切入点匹配的执行点称作连接点。如果说切入点是查询条件,那连接点就是被选中的具体的查询结果。程序执行的某个特定位置,程序能够应用增强代码的一个“时机”,比如方法调用或者特定异常抛出。
-
切面(Aspect):切点和增强组成切面。它包括了横切逻辑的定义,也包括了连接点的定义。Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
-
目标对象(Target object):增强逻辑的织入的目标类
-
AOP代理(AOP proxy):AOP框架创建的对象。一个类被AOP织入增强之后,就产生了一个结果类,它是融合了原类和增强逻辑的代理类。
-
织入(Weaving):将增强添加到目标类具体连接点上的过程。AOP有三种织入的方式:编译期织入、类装载期织入、动态代理织入(spring采用动态代理织入)
AOP使用方法
- 有个目标方法(就是有一个需要增强的方法)
- 增强处理,编写增强的业务。
public class PrepositionExtra{
Logger logger = Logger.getLogger(PrepositionExtra.class);
/**
* 前置增强
* Arrays.toString(joinPoint.getArgs()):连接点方法参数数组
* @param joinPoint 连接点对象
*/
public void beforeMethod(JoinPoint joinPoint){
logger.debug("前置增强:" + joinPoint.getSignature().getName() + Arrays.toString(joinPoint.getArgs()));
}
/**
* 一个后置增强
* getThis():连接点方法所在的目标类
* getSignature():连接点方法信息
* @param joinPoint
* @param o
*/
public void afterMethod(JoinPoint joinPoint, Object o){
logger.debug("后置增强:" + joinPoint.getThis() + joinPoint.getSignature());
}
}
- 定义切入点,切入点:简单的说,就是连接点的查询条件
<!--配置额外功能的bean标签-->
<bean id="pe" class="com.kgc.extra.PrepositionExtra"></bean>
<aop:config>
<!--切入点表达式:expression(返回值类型 精确到方法的全限定名)-->
<aop:pointcut id="pt" expression="execution(* com.kgc.*.*.*(..))"/>
<!--ref:增强处理对象-->
<aop:aspect ref="pe">
<!--前置增强处理 method:被织入的方法。pointcut-ref:切入点-->
<aop:before method="beforeMethod" pointcut-ref="pt"></aop:before>
<!--后置增强处理-->
<aop:after-returning method="afterMethod" pointcut-ref="pt" returning="o"></aop:after-returning>
</aop:aspect>
</aop:config>
- 补充:表达式匹配规则举例
- public * addNewUser(entity.User): “*”表示匹配所有类型的返回值。
- public void (entity.User): “”表示匹配所有方法名。
- public void addNewUser(…): “…”表示匹配所有参数个数和类型。
- com.service..(…):匹配com.service包下所有类的所有方法。
- com.service….(…):匹配com.service包及其子包下所有类的所有方法
异常抛出增强
- 异常抛出增强的特点
- 在目标方法抛出异常时织入增强处理
- 可拔插的异常处理方案
- <aop:after-throwing>元素:定义异常抛出增强
<aop:config>
<!--
异常抛出增强
ref:引用包含增强方法的Bean
method:将afterThrowing()方法定义为异常抛出增强
pointcut-ref:引用pointcut切入点
throwing:为e的参数注入异常实例
-->
<aop:aspect ref="pe">
<aop:after-throwing method="xx" pointcut-ref="xx" throwing="e"/>
</aop:aspect>
</aop:config>
最终增强
- 无论方法是否抛出异常,都会在目标方法最后织入增强处理,即:该增强都会得到执行
- 类似于异常处理机制中finally块的作用,一般用于释放资源
- 可以为各功能模块提供统一的,可拔插的处理方案
- <aop:after>元素:定义最终增强
环绕增强
-
目标方法前后都可织入增强处理
-
功能最强大的增强处理
-
可获取或修改目标方法的参数、返回值,可对它进行异常处理,甚至可以决定目标方法是否执行
-
<aop:around>元素:定义环绕增强
-
增强处理类型
-
Spring AOP配置元素
代理设计模式
- 代理模式可以细分为 静态代理和动态代理
- 静态代理的特点:创建一个代理类,具备和目标类相同的方法,对目标类的方法进行功能的增强。
- 静态代理的代码要求:
- 代理类和目标类需要实现相同的接口
- 代理类需要持有目标类的对象
- 静态代理的优点:将代理类和目标类解耦合
- 静态代理的缺点:使用静态代理会产生大量的代理类
- 静态代理和动态代理的区别?
- 静态代理在代码编译的时候,代理类已经存在了
- 动态代理在运行期才会生成代理类和代理对象。在运行期,JDK底层会动态生成代理类,并且创建他的对象供程序使用