Spring 核心内容
概述
1、Spring 是轻量级的开源的 JavaEE 框架
2、Spring 可以解决企业应用开发的复杂性
3、Spring 有两个核心部分:IOC 和 Aop
(1)IOC(Inversion of Control):控制反转,把创建对象过程交给 Spring 进行管理。
DI(Dependency Injection ):通过配置文件给属性赋值
(2)Aop(Aspect Oriented Programming):面向切面,不修改源代码进行功能增强
4、Spring 特点(优点)
1、低侵入式设计:非入侵式设计,基于Spring开发的应用一般不依赖于Spring的类
2、独立于各种应用服务器,真正实现:一次编写,到处运行。
3、Spring的依赖注入特性使Bean与Bean之间的依赖关系变的完全透明,降低了耦合度:使用SpringIOC容器,将对象之间的依赖关系交给Spring,降低组件之间的耦合性,让我们更专注于应用逻辑
4、它的面向切面编程特性允许将一些通用任务如安全、事务、日志等进行集中式处理
5、并且它还提供了与第三方持久层框架的良好整合,并简化了底层数据库访问
6、高度的开放性(可以和Struts2、Hibernate、MyBatis、CXF等很多主流第三方框架无缝整合)
1、IOC
控制反转,把创建对象过程交给 Spring 进行管理。类似工厂模式
组件化的思想:分离关注点,使用接口,不再关注实现
依赖的注入:将组件的构建和使用分开
设值注入
使用元素定义一个组件
id属性:指定一个用来访问的唯一名称
name属性:指定多个别名,名字之间使用逗号、分号或空格进行分隔
<bean id="no1" class="no1.cn.service.No1">
<property name="userName1" value="用户一"/>
<property name="userName2" value="用户二"/>
<property name="context1" value="hello,I'm 用户一!"/>
<property name="context2" value="hello,I'm 用户一!"/>
</bean>
2、AOP
概念:面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(不通过修改源代码方式,在主干功能里面添加新功能)
AOP是一种思想,它与具体的实现技术无关,任何一种符合AOP的思想的技术实现,都可以看做是AOP的实现。通过java的动态代理机制,就可以很容易实现AOP的思想,实际上Spring的AOP也是建立在Java的代理机制上。
2.1相关术语
- 增强(Adivce):又翻译成通知,定义了切面是什么以及何时使用,描述了切面要完成的工作和何时需要执行这个工作。是织入到目标类连接点上的一段程序代码。增强包含了用于添加到目标连接点上的一段执行逻辑,又包含了用于定位连接点的方位信息。(所以spring提供的增强接口都是带方位名:BeforeAdvice、(表示方法调用前的位置)AfterReturninAdvice、(表示访问返回后的位置)ThrowAdvice等等,所以只有结合切点和增强两者一起才能确定特定的连接点并实施增强逻辑)
- 切入点(Pointcut):Advice定义了切面要发生“故事”和时间,那么切入点就定义了“故事”发生的地点。例如某个类或者方法名,Spring中允许我们使用正则来指定。
- 连接点(Joinpoint):切入点匹配的执行点称作连接点。如果说切入点是查询条件,那连接点就是被选中的具体的查询结果。程序执行的某个特定位置,程序能够应用增强代码的一个“时机”,比如方法调用或者特定异常抛出
- 切面(Aspect):切点和增强组成切面。它包括了横切逻辑的定义,也包括了连接点的定义。Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中
- 代理(Proxy):AOP框架创建的对象。一个类被AOP织入增强之后,就产生了一个结果类,它是融合了原类和增强逻辑的代理类。
- 目标对象(Target):增强逻辑的织入的目标类
- 织入(Weaving):将增强添加到目标类具体连接点上的过程。AOP有三种织入的方式:编译期织入、类装载期织入、动态代理织入(spring采用动态代理织入)
a)连接点:类里面哪些方法可以被增强,这些方法称为连接点
b)切入点:实际被真正增强的方法称为切入点
c)通知(增强):实际增强的逻辑部分称为通知,且分为以下五种类型:
1)前置通知 2)后置通知 3)环绕通知 4)异常通知 5)最终通知
2.2 使用aop记录日志
在配置文件使用aop配置
首先添加aop需要的jar包
package no1.cn.service;
模拟编写业务层,添加方法
public class No1 {
private String userName1;
private String userName2;
private String context1;
private String context2;
public String getUserName1() {
return userName1;
}
public void setUserName1(String userName1) {
this.userName1 = userName1;
}
public String getUserName2() {
return userName2;
}
public void setUserName2(String userName2) {
this.userName2 = userName2;
}
public String getContext1() {
return context1;
}
public void setContext1(String context1) {
this.context1 = context1;
}
public String getContext2() {
return context2;
}
public void setContext2(String context2) {
this.context2 = context2;
}
public void work(){
System.out.println(userName1+"说:\""+context1+"\"");
System.out.println(userName2+"说:\""+context2+"\"");
}
}
编写增强类,写具体增强的方法
package no3.cn;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import java.util.Arrays;
public class Advice {
private static Logger log=Logger.getLogger(Advice.class);
public void before(JoinPoint jp) {
log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().
getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
}
public void afterReturning(JoinPoint jp, Object result) {
log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().
getName() + " 方法。方法返回值:" + result);
}
}
在xml文件中新增
xmlns:aop="http://www.springframework.org/schema/aop"
在 xsi:schemaLocation中新增
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
配置spring 文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--为No1各属性赋值-->
<bean id="no1" class="no1.cn.service.No1">
<property name="userName1" value="用户一"/>
<property name="userName2" value="用户二"/>
<property name="context1" value="hello,I'm 用户一!"/>
<property name="context2" value="hello,I'm 用户一!"/>
</bean>
<!-- 定义通知类-->
<bean id="advice" class="no3.cn.Advice"/>
<!-- 配置aop-->
<aop:config >
<!-- 定义切点, expression定义要拦截的方法,此处表示为no1包下所有方法-->
<aop:pointcut id="myCut" expression="execution(* no1..*.*(..))"/>
<!-- 配置切面 ,引入增强处理对象-->
<aop:aspect ref="advice">
<!-- 引入前置增强、后置增强对应的具体增强方法-->
<aop:before method="before" pointcut-ref="myCut" />
<aop:after-returning method="afterReturning" pointcut-ref="myCut" returning="result"/>
</aop:aspect>
</aop:config>
</beans>
注意:
编写测试类,测试记录日志
package no1.cn.test;
import no1.cn.service.No1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestNo1 {
@Test
public void work() {
ApplicationContext applicationContext1 = new ClassPathXmlApplicationContext("applicationContext1.xml");
No1 no1 = (No1) applicationContext1.getBean("no1");
no1.work();
}
}
运行结果 如下
11-15 18:33:40[INFO]no3.cn.Advice
-调用 no1.cn.service.No1@672872e1 的 work 方法。方法入参:[]
用户一说:"hello,I'm 用户一!"
用户二说:"hello,I'm 用户一!"
11-15 18:33:40[INFO]no3.cn.Advice
-调用 no1.cn.service.No1@672872e1 的 work 方法。方法返回值:null