目录
- 一、搭建Spring环境
- 二、编写配置文件
- 三、开发Spring程序 (IOC)
- 四、依赖注入的三种方式:
- 五、各种集合类型的属性注入
- 六、自动装配 (只适用于 ref 类型)
- 七、使用注解定义 bean
- 八、使用注解实现事务(声明式事务)
- 九、基于XML 开发Spring AOP
- 十、基于注解 开发Spring AOP
- 十一、使用 Spring 开发 Web 项目
一、搭建Spring环境
下载 jar 包
① spring-aop.jar (开发AOP特性时需要的 jar)② spring-beans.jar (管理Bean的 jar)
③ spring-context.jar (处理spring上下文的 jar)
④ spring-core.jar (spring核心 jar)
⑤ spring-expression.jar (spring表达式 jar)
⑥ commons-logging.jar (三方提供,日志 jar)
二、编写配置文件
为了编写时有一些提示或自动生成一些配置信息,需要增加插件:spring tool suite (sts)
新建名为 applicationContext.xml 的 Spring Bean Configuration File① 在配置文件 applicationContext.xml 中加入:
<!-- 该文件中产生的所有对象,被Spring放入了一个称之为SpringIOC容器的地方 -->
<!-- id:唯一标识符 class:指定类型 -->
<bean id="student" class="org.lanqiao.entity.Student">
<!--
property:该class所代表的类的属性
name:属性名
value:属性值
-->
<property name="stuNo" value="1"></property>
<property name="stuName" value="ls"></property>
<property name="stuAge" value="19"></property>
</bean>
② 测试:
//Spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//执行从SpringIOC容器中获取一个id为student的对象
Student student = (Student)context.getBean("student");
System.out.println(student.toString());
③ 运行结果:
三、开发Spring程序 (IOC)
IOC (控制反转) 也可以称之为DI (依赖注入):
控制反转:将 创建对象,属性值的方式 进行了翻转,从 new,setXxx() 翻转为了从 SpringIOC容器 getBean()依赖注入:将属性值注入给了属性,将属性注入给了Bean,将Bean注入给了IOC容器。
总结:IOC/DI 无论需要什么对象,都可以直接去SpringIOC容器中获取,而不需要自己操作 (new / setXxx)
IOC容器赋值:
①如果是 简单类型 ,使用 value ;②如果是 对象类型 ,ref = "需要引用的id值" ,因此实现了 对象与对象之间的依赖关系
context.getBean(需要获取的bean的id值)
四、依赖注入的三种方式:
(1) 通过set方式赋值
【 通过setXxx() 赋值,默认使用的set方法;依赖注入底层时通过 反射 实现的 】
① appicationContext.xml 中添加 Bean
<bean id="teacher" class="org.lanqiao.entity.Teacher">
<!-- 通过set方式赋值 -->
<property name="name" value="zs"></property>
<property name="age" value="20"></property>
</bean>
<bean id="course" class="org.lanqiao.entity.Course">
<!-- 通过set方式赋值 -->
<property name="courseName" value="java"></property>
<property name="courseHour" value="200"></property>
<!-- 将teacher对象注入到course对象中 -->
<property name="teacher" ref="teacher"></property>
</bean>
② 测试代码:
public static void testDI() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Course course = (Course)context.getBean("course");
course.showInfo();
}
③ 运行结果:
(2) 通过构造器赋值
【通过 构造方法 赋值】
① appicationContext.xml 中添加 Bean
<bean id="teacher" class="org.lanqiao.entity.Teacher">
<!-- 通过构造器赋值 -->
<constructor-arg value="李四"></constructor-arg>
<constructor-arg value="30"></constructor-arg>
</bean>
<bean id="course" class="org.lanqiao.entity.Course">
<!-- 通过构造器赋值 (参数顺序不一致,可通过index,name,type等指定参数)-->
<constructor-arg value="C语言"></constructor-arg>
<constructor-arg value="150"></constructor-arg>
<constructor-arg ref="teacher"></constructor-arg>
</bean>
② 测试代码:
public static void testDI() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Course course = (Course)context.getBean("course");
course.showInfo();
}
③ 运行结果:
(3) p命名空间注入
【引入p命名空间】
也可以直接在 appicationContext.xml 的头文件中添加:
xmlns:p="http://www.springframework.org/schema/p"
① appicationContext.xml 中添加 Bean
<bean id="teacher" class="org.lanqiao.entity.Teacher" p:age="25" p:name="王五">
</bean>
<bean id="course" class="org.lanqiao.entity.Course" p:courseName="Python" p:courseHour="120" p:teacher-ref="teacher">
</bean>
② 测试代码:
public static void testDI() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Course course = (Course)context.getBean("course");
course.showInfo();
}
③ 运行结果:
五、各种集合类型的属性注入
【set,list,数组各自都有自己的标签< set >< list >< array > ,但也可以混着用,例如set也可以用< list >< array >】
① 在 appicationContext.xml 中加入:
<!-- 各种集合类型的属性注入 -->
<bean id="CollectionDemo" class="org.lanqiao.entity.CollectionDemo">
<!-- 列表类型 -->
<property name="listElement">
<list>
<value>java1</value>
<value>html1</value>
<value>php1</value>
</list>
</property>
<!-- 数组类型 -->
<property name="arrayElement">
<array>
<value>java2</value>
<value>html2</value>
<value>php2</value>
</array>
</property>
<!-- set 类型 -->
<property name="setElement">
<set>
<value>java3</value>
<value>html3</value>
<value>php3</value>
</set>
</property>
<!-- map 类型 -->
<property name="mapElement">
<map>
<entry>
<key>
<value>111</value>
</key>
<value>java4</value>
</entry>
<entry>
<key>
<value>222</value>
</key>
<value>html4</value>
</entry>
<entry>
<key>
<value>333</value>
</key>
<value>php4</value>
</entry>
</map>
</property>
<!-- properties 类型 -->
<property name="propertiesElement">
<props>
<prop key="555">java5</prop>
<prop key="666">html5</prop>
<prop key="777">php5</prop>
</props>
</property>
</bean>
② 测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
CollectionDemo collectionDemo = (CollectionDemo)context.getBean("CollectionDemo");
System.out.println(collectionDemo.toString());
③ 运行结果:
六、自动装配 (只适用于 ref 类型)
【自动装配虽然可以减少代码量,但是会降低程序的可读性,使用时需要谨慎。】
(1) 测试自动装配
① 在 appicationContext.xml 中加入:
<bean id="teacher" class="org.lanqiao.entity.Teacher" p:age="25" p:name="王五">
</bean>
<!-- byName 按id自动装配course的teacher对象-->
<bean id="course" class="org.lanqiao.entity.Course" autowire="byName">
<property name="courseName" value="zs"></property>
<property name="courseHour" value="20"></property>
</bean>
② 测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Course course = (Course)context.getBean("course");
course.showInfo();
③ 运行结果
(2) 自动装配的几种常见类型:
① byName: 自动寻找:其他bean的id值=该Course类的属性名(例:course 中的 teacher)
② byType: 其他bean的类型(class) 是否与 该Course类的ref属性类型一致 (注意,此种方式 必须满足:当前Ioc容器中 只能有一个Bean满足条件 )
③ constructor: 其他bean的类型(class) 是否与 该Course类的构造方法参数 的类型一致;此种方式的本质就是byType
(3) 将ioc容器的所有bean 统一设置成自动装配
在 applicationContext.xml 头文件中添加:default-autowire="byName" 一次性将该ioc容器的所有bean 统一设置成自动装配七、使用注解定义 bean
通过注解的形式 将bean以及相应的属性值 放入ioc容器
(1) 在appicationContext.xml 的头文件中添加:
xmlns:context="http://www.springframework.org/schema/context"
(2) 在appicationContext.xml 的中添加:
<context:component-scan base-package="org.lanqiao.entity"></context:component-scan>
Spring在启动的时候,会根据 base-package在 该包中扫描所有类,查找这些类是否有注解@Component("studentDao"),如果有,则将该类 加入spring Ioc容器。
@Component细化:
① dao层注解:@Repository
② service层注解:@Service
③ 控制器层注解:@Controller
八、使用注解实现事务(声明式事务)
通过事务 使方法 要么全成功、要么全失败
(1) 放入jar包:
① spring-tx-4.3.9.RELEASE②mysql-connector-java-8.0.19.jar
③commons-dbcp.jar 连接池使用到数据源
④commons-pool.jar 连接池
⑤spring-jdbc-4.3.9.RELEASE.jar
⑥aopalliance.jar
(2) 配置
① 增加事务 tx 的命名空间
xmlns:tx="http://www.springframework.org/schema/tx"
② 增加对事务的支持
<tx:annotation-driven transaction-manager="txManager" />
从下往上补全:
<!-- 配置数据库相关 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.jdbc.cj.mysql.driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/jdbc?serverTimezone=UTC"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
<property name="maxActive" value="10"></property>
<property name="maxIdle" value="6"></property>
</bean>
<!-- 配置事务管理器txManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 增加对事务的支持 -->
<tx:annotation-driven transaction-manager="txManager" />
(3) 使用:
将需要 成为事务的方法 前增加注解:
@Transactional(readOnly=false,propagation=Propagation.REQUIRED)
九、基于XML 开发Spring AOP
通知实现步骤 :
(1) 添加 jar 包
① aopaliance.jar
② aspectjweaver.jar
(2) 编写 方法
① 通知类 XmlAdvice.java:
public class XmlAdvice {
public void before(){
System.out.println("这是前置通知...");
}
public void after(){
System.out.println("这是后置通知...");
}
}
② service 接口 IStudentService:
public interface IStudentService {
public void addStudent();
public void deleteStudent();
}
③ IStudentService 接口的实现类 StudentServiceImpl :
public class StudentServiceImpl implements IStudentService{
@Override
public void addStudent() {
System.out.println("添加学生....");
// int x = 5/0; //异常:测试异常通知
}
@Override
public void deleteStudent() {
System.out.println("删除学生");
}
}
(3) 配置 ApplicationContext.xml
① 先在 头文件 中加入 命名空间:
xmlns:aop="http://www.springframework.org/schema/aop"
② 注册bean 和 指定切点切面以及各种通知
<!-- 注册bean -->
<bean id="studentService" class="org.lanqiao.service.impl.StudentServiceImpl"></bean>
<bean id="xmlAdvice" class="org.lanqiao.aop.XmlAdvice"></bean>
<!-- 指定切点 -->
<aop:config>
<aop:pointcut expression="execution(public void org.lanqiao.service.impl.StudentServiceImpl.*(..))" id="pointcut"/>
<!-- 指定切面 -->
<aop:aspect ref="xmlAdvice">
<!-- 指定前置通知 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<!-- 指定后置通知 -->
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
(4) 测试 前置通知 和 后置通知
① 测试代码:
public static void testAOP() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
IStudentService studentService = (IStudentService)context.getBean("studentService");
studentService.addStudent();
studentService.deleteStudent();
}
② 运行结果:
(5) 测试:使用环绕通知实现前置,后置,异常通知
① 通知类 XmlAdvice.java 中加入around 方法
public Object around(ProceedingJoinPoint point) {
Object result = null;
try{
System.out.println("这是环绕通知实现的[前置通知]...");
result = point.proceed(); //执行目标方法,addStudent()
System.out.println("这是环绕通知实现的[后置通知]...");
}catch(Throwablee){
System.out.println("这是环绕通知实现的[异常通知]...");
e.printStackTrace();
}
return result;
}
② 注册bean 和 指定切点切面以及各种通知:
<!-- 注册bean -->
<bean id="studentService" class="org.lanqiao.service.impl.StudentServiceImpl"></bean>
<bean id="xmlAdvice" class="org.lanqiao.aop.XmlAdvice"></bean>
<aop:config>
<!-- 指定切点 (StudentService中的所有方法) -->
<aop:pointcut expression="execution(public void org.lanqiao.service.impl.StudentServiceImpl.*(..))" id="pointcut"/>
<!-- 指定切面 -->
<aop:aspect ref="xmlAdvice">
<!-- 指定环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
③ 测试代码:**
public static void testAOP() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
IStudentService studentService = (IStudentService)context.getBean("studentService");
studentService.addStudent();
}
④ 运行结果:**
十、基于注解 开发Spring AOP
实现步骤:
(1) 添加 jar 包 (与 xml 方式 jar包相同)
① aopaliance.jar
② aspectjweaver.jar
(2) 编写 方法:
① IStudentService 接口的实现类
与 xml 不同之处: 使用注解注册bean
@Service("studentService") //等价于<bean id="studentService"
StudentServiceImpl :
@Service("studentService") //等价于<bean id="studentService" class="org.lanqiao.service.impl.StudentServiceImpl">
public class StudentServiceImpl implements IStudentService{
@Override
public void addStudent() {
System.out.println("添加学生....");
int x = 5/0; //异常:测试异常通知
}
}
② 通知类 XmlAdvice
与 xml 不同之处:
//使用注解注册bean
@Component("xmlAdvice")
//指定切面
@Aspect //通知
//指定环绕通知(指定切点)
@Around("execution(public * addStudent())")
XmlAdvice.java
@Component("xmlAdvice") //等价于<bean id="xmlAdvice" class="org.lanqiao.aop.XmlAdvice">
@Aspect //通知
public class XmlAdvice {
@Around("execution(public * addStudent())")
public Object around(ProceedingJoinPoint pj) {
Object result = null;
try{
System.out.println("这是环绕通知实现的前置通知");
result = pj.proceed(); //执行目标方法:addStudent()
System.out.println("这是环绕通知实现的后置通知");
}catch(Throwable e){
System.out.println("这是环绕通知实现的异常通知");
System.out.println("异常类型:" + e.getMessage().toString());
}
return result;
}
}
(3) 配置 ApplicationContext.xml
① 先在 头文件 中加入 命名空间:
xmlns:aop="http://www.springframework.org/schema/aop"
② 设置扫描包 和 开启自动代理支持
<!-- 扫描包 -->
<!-- 扫描 studentService,xmlAdvice 这两个bean -->
<context:component-scan base-package="org.lanqiao.aop , org.lanqiao.service"></context:component-scan>
<!-- 开启 @aspectj 的自动代理支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
(4) 测试 使用环绕通知实现前置,后置,异常通知
① 测试代码:
public static void testAOP() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
IStudentService studentService = (IStudentService)context.getBean("studentService");
studentService.addStudent();
}
② 运行结果:
(5) 测试 多个切面的优先级
① 切面一 : Advice
order=1 值越小 优先级越高 (此时先执行后退出)
@Component("Advice")
@Aspect //指定切面
@Order(1) //值越小 优先级越高
public class Advice {
@Before("execution(public * addStudent())") //指定切点
public void before() {
System.out.println("这是 切面Advice 的前置通知");
}
@After("execution(public * addStudent())") //指定切点
public void after() {
System.out.println("这是 切面Advice 的后置通知");
}
}
② 切面二 : XmlAdvice:
@Order(3) 值越小 优先级越高 (此时后执行先退出)
@Component("xmlAdvice") //等价于<bean id="xmlAdvice" class="org.lanqiao.aop.XmlAdvice">
@Aspect //通知
@Order(3) //值越小 优先级越高
public class XmlAdvice {
@Before("execution(public * addStudent())") //指定切点
public void before() {
System.out.println("这是 切面XmlAdvice 的前置通知....");
}
@After("execution(public * addStudent())")
public void after() {
System.out.println("这是 切面XmlAdvice 的后置通知....");
}
}
③ 运行结果:
十一、使用 Spring 开发 Web 项目
1、Web项目如何初始化SpringIOC容器
思路:当服务启动时(tomcat),通过监听器将SpringIOC容器初始化一次(该监听器 spring-web.jar已经提供)
因此用spring开发web项目 至少需要7个jar:
① spring-aop.jar (开发AOP特性时需要的 jar)② spring-beans.jar (管理Bean的 jar)
③ spring-context.jar (处理spring上下文的 jar)
④ spring-core.jar (spring核心 jar)
⑤ spring-expression.jar (spring表达式 jar)
⑥ commons-logging.jar (三方提供,日志 jar)
⑦ spring-web.jar
[ 注意:web项目的jar包 是存入到WEB-INF/lib中,否则后面可能会报错 ]
IOC容器初始化: web项目启动时 ,会自动加载web.xml,因此需要在web.xml中加载 监听器。
2、 web.xml 添加配置 :
(1) 指定IOC容器的位置
① web.xml :
<!-- 指定IOC容器 (applicationContext.xml) 的位置-->
<context-param>
<!-- 监听器的父类ContextLoader中有一个属性contextConfigLocation,该属性值保存着容器配置的文件applicationContext.xml -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<!-- 配置spring-web.jar提供的监听器,此监听器可以在服务器启动时 初始化IOC容器
初始化IOC容器 (applicationContext.xml)
1:必须告诉监听器此容器的位置:context-param
2:默认约定的位置:WEB-INF/applicationContext.xml (xml文件名也不能改)
-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
② 运行结果:
(2) 不指定IOC容器的位置
将 applicationContext.xml 放在默认约定的位置:WEB-INF/applicationContext.xml
(xml文件名也不能改)
① web.xml :
<listener>
<!-- 配置spring-web.jar提供的监听器,此监听器可以在服务器启动时 初始化IOC容器
初始化IOC容器 (applicationContext.xml)
1:必须告诉监听器此容器的位置:context-param
2:默认约定的位置:WEB-INF/applicationContext.xml (xml文件名也不能改)
-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
②运行结果:
3、拆分 Spring 配置文件
(1) 按三层架构分:
① Dao:applicationContextDao.xml
② Service:applicationContextService.xml
③ Controller:applicationContextController.xml
(2) 加载多个配置文件:
① 方法一:param-value 中以逗号分隔:
<!-- 指定IOC容器 (applicationContext.xml) 的位置 -->
<context-param>
<!-- 监听器的父类ContextLoader中有一个属性contextConfigLocation,该属性值保存着容器配置的文件applicationContext.xml -->
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml,
classpath:applicationContextDao.xml,
classpath:applicationContextService.xml,
classpath:applicationContextController.xml
</param-value>
</context-param>
<listener>
<!-- 配置spring-web.jar提供的监听器,此监听器可以在服务器启动时 初始化IOC容器
初始化IOC容器 (applicationContext.xml)
1:必须告诉监听器此容器的位置:context-param
2:默认约定的位置:WEB-INF/applicationContext.xml (xml文件名也不能改)
-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
运行结果:
② (推荐) 方法二:param-value 中用 * :
<!-- 指定IOC容器 (applicationContext.xml) 的位置 -->
<context-param>
<!-- 监听器的父类ContextLoader中有一个属性contextConfigLocation,该属性值保存着容器配置的文件applicationContext.xml -->
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext*.xml,
</param-value>
</context-param>
<listener>
<!-- 配置spring-web.jar提供的监听器,此监听器可以在服务器启动时 初始化IOC容器
初始化IOC容器 (applicationContext.xml)
1:必须告诉监听器此容器的位置:context-param
2:默认约定的位置:WEB-INF/applicationContext.xml (xml文件名也不能改)
-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
运行结果:
③ (不推荐) 方法三:param-value 中只写主配置:
其他配置文件 在 主配置文件 applicationContext.xml中 使用 <import resource=""/>
加入