下载地址
需要的架包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
优点
- Spring是一个开源的免费的框架(容器)
- Spring是一个轻量级,非入侵式的框架
- 控制反转(ioc),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
- Spring是一个开发JavaEE应用程序的轻量级的一站式框架。
Spring框架的组成
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
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。
Spring配置
IOC和DI(在配置文件加载的时候,容器中管理的对象就已经初始化了)
- IOC:控制反转,对象由容器创建, 传统的java对象的创建方式,是以new的方式在程序中硬编码创建的。所谓的“反转”指的是,对象的创建方式不是由程序员通过编码方式创建,而是通过spring容器创建。由容器创建对象。控制反转就是容器托管对象
- DI:依赖注入,由容器对依赖关系进行初始化赋值
IOC创建对象方式
先创建实体类
public class Person {
private String name; //姓名
private String speaking; //说的话
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSpeaking() {
return speaking;
}
public void setSpeaking(String speaking) {
this.speaking = speaking;
}
public void show() {
System.out.println(this.name+" 说:" + this.speaking);
}
}
打开applicationContext.xml,配置Person类
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- id唯一标识 Person person = new Person(); -->
<bean id="person" class="com.gec.spring.bean.Person">
<property name="name" value="李四"></property>
<property name="speaking" value="hello world!"></property>
</bean>
</beans>
测试
public static void main(String[] args) {
//获取spring的对象容器 上下文
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("person");
person.show();
}
DI依赖注入方式
- setter注入:需要有setter方法
ref:引用Spring容器中创建好的对象 value:基本数据类型
第一种:setter注入
<bean id="display" class="com.gec.spring.bean.Display"></bean>
<bean id="host" class="com.gec.spring.bean.Host"></bean>
<bean id="computer" class="com.gec.spring.bean.Computer">
<property name="display" ref="display"></property>
<property name="host" ref="host"></property>
</bean>
第二种:p命名空间注入:需要依赖第三方约束
<bean id="computer" class="com.gec.spring.bean.Computer" p:display-ref="display" p:host-ref="host">
</bean>
- 构造器注入
<bean id="computer" class="com.gec.spring.bean.Computer">
<constructor-arg index="0" ref="host"></constructor-arg>
<constructor-arg index="1" ref="display"></constructor-arg>
</bean>
- 特殊类型的注入(集合),常用于框架的配置
创建实体类
public class Department {
private String name;
//定义员工列表数据
private List<Employee> empList;
private Set<Employee> empSet;
private Map<String, Employee> empMap;
private Properties pp;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Employee> getEmpList() {
return empList;
}
public void setEmpList(List<Employee> empList) {
this.empList = empList;
}
public Set<Employee> getEmpSet() {
return empSet;
}
public void setEmpSet(Set<Employee> empSet) {
this.empSet = empSet;
}
public Map<String, Employee> getEmpMap() {
return empMap;
}
public void setEmpMap(Map<String, Employee> empMap) {
this.empMap = empMap;
}
public Properties getPp() {
return pp;
}
public void setPp(Properties pp) {
this.pp = pp;
}
}
使用 list、set、map、props注入集合关系:
<bean id="department" class="com.gec.spring.bean.Department">
<property name="name" value="财务部"></property>
<property name="empList">
<list>
<!--如果是基本类型,用value-->
<ref bean="emp1"/>
<ref bean="emp2"/>
</list>
</property>
<property name="empSet">
<set>
<ref bean="emp1"/>
<ref bean="emp2"/>
</set>
</property>
<property name="empMap">
<map>
<entry key="1" value-ref="emp1"></entry>
<entry key="2" value-ref="emp2"></entry>
</map>
</property>
<property name="pp">
<props>
<prop key="pp1">hello</prop>
<prop key="pp2">world</prop>
</props>
</property>
</bean>
<bean id="emp1" class="com.gec.spring.bean.Employee">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean>
<bean id="emp2" class="com.gec.spring.bean.Employee">
<property name="id" value="2"></property>
<property name="name" value="李四"></property>
</bean>
-
接口注入
-
注解注入
1.导入约束:context约束 2.配置注解的支持:<context:annotation-config></context:annotation-config>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启注解配置 -->
<context:annotation-config></context:annotation-config>
@Autowired:
直接在属性上使用即可,也可以字set方法上使用
使用Autowired我们可以不用再写set方法,前提是自动装配的属性在IOC容器中存在
public class User {
private String name;
@Autowired
private Dog dog;
@Autowired
private Cat cat;
public User() {
System.out.println("454545");
}
@Component,@Value
<!-- 指定要扫描的包,这个包下的注解就会生效 -->
<context:component-scan base-package="com.kuang.pojo"></context:component-scan>
<!-- 开启注解配置 -->
<context:annotation-config></context:annotation-config>
//相当于<bean id="user" class="com.kuang.pojo.User"></bean>
@Component
public class User {
@Value("张三")
public String name;
}
Bean的作用域
Sping的自动装配
byName
<bean id="computer" class="com.gec.spring.bean.Computer" autowire="byName"></bean>
byType
<bean id="computer" class="com.gec.spring.bean.Computer" autowire="byType"></bean>
使用Java的方式配置Spring
实体类
@Component
public class User {
@Value("张三")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置类
//代表这是一个配置类,和之前的beans.xml是一样的
//也会被spring容器托管,因为它本身就是一个@Component
@Configuration
@ComponentScan("com.kuang.pojo")//扫描包
//还可以通过import注解引入其他配置类
public class KuangConfig {
//注册Bean,相当于xml文件里的bean标签
//方法名相当于bean标签的id属性,返回值相当于class属性
@Bean
public User getUser(){
return new User();
}
}
测试
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);
User getUser = (User) context.getBean("getUser");
System.out.println(getUser.getName());
}
}
Spring的AOP编程
介绍
在不影响业务本来的情况下,实现动态增加功能,大量应用再日志,事务。。等等
(1)AOP Aspect Oriented Programming 面向切面编程,其实就是拦截器。
(2)JavaEE应用中,常见的“拦截”的技术:
原生平台中的Filter, 过滤器。过滤的是一切可访问的资源,包括,页面,图片,样式,servle/jsp。
Spring中的AOP, 主要是拦截业务层的方法。对业务方法的功能增强。
MVC框架,也提供了拦截器。拦截的是控制器,主要是action(Struts2), handler(springmvc).
(3) 拦截的概念:对目标对象的代理,并进行功能的增强。简单来说,就是增强功能。
对于“共性”的问题,如果OOP解决不了的,可以使用AOP来解决“通用性”的问题。AOP是对OOP的补充的作用。也就是解决通用性问题。作用:降低耦合度。
(4)aop编程的术语
- aspect 切面 对共性问题的抽象 , 拦截器类
- pointcut 切入点 被拦截的方法
- advice 通知,功能增强, 增强的方式:前置增强,后置增强,环绕增强,异常增强,最终增强。
导包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
AOP编程的实现方式
- 实现接口的方式(spring低版本)
- schema的方式(使用XML配置)
MyAspect类,拦截器类
/**
* 拦截器类
* @author gec
*
*/
public class MyAspect {
//1. 前置增强(XML配置)
public void before(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs(); //获取被拦截方法的参数列表
String methodName = joinPoint.getSignature().getName(); //被拦截方法的名称
Object target = joinPoint.getTarget(); //拦截的目标实例(业务类的实例)
//进一步完成功能 的增强
System.out.println("前置方法名:"+methodName+",参数列表:"+Arrays.toString(args)+",目标对象实例:"+target);
}
//2. 后置增强(XML配置)
public void afterReturning(JoinPoint joinPoint,Object returnValue) {
Object[] args = joinPoint.getArgs(); //获取被拦截方法的参数列表
String methodName = joinPoint.getSignature().getName(); //被拦截方法的名称
Object target = joinPoint.getTarget(); //拦截的目标实例(业务类的实例)
//进一步完成功能 的增强
System.out.println("后置方法名:"+methodName+",参数列表:"+Arrays.toString(args)+",目标对象实例:"+target+",业务方法的返回值 :"+returnValue);
}
//3. 环绕增强
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs(); //获取被拦截方法的参数列表
String methodName = pjp.getSignature().getName(); //被拦截方法的名称
Object target = pjp.getTarget(); //拦截的目标实例(业务类的实例)
System.out.println("环绕-前置方法名:"+methodName+",参数列表:"+Arrays.toString(args)+",目标对象实例:"+target);
Object returnValue = pjp.proceed(); //调用核心业务方法
System.out.println("环绕-后置方法名:"+methodName+",参数列表:"+Arrays.toString(args)+",目标对象实例:"+target+",业务方法的返回值 :"+returnValue);
return returnValue;
}
}
拦截器的配置 ,要先添加aop的命名空间
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!-- 容器托管业务类,拦截器类 -->
<bean id="userService" class="com.gec.spring.service.impl.UserServiceImpl"></bean>
<bean id="myAspect" class="com.gec.spring.aop.MyAspect"></bean>
<!-- aop的织入 -->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(public * com.gec.spring.service.impl.*.*(..))" />
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" returning="returnValue" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
测试 业务类返回的是代理业务接口,不能使用实现类接收
public class TestAspect {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
//返回的是代理业务接口(被增强后),不能用实现类接收
UserService userService = (UserService) context.getBean("userService");
String msg = userService.findUserById("001");
System.out.println(msg);
}
}
结果
- 注解的方式
在切面类中添加注解配置
/**
* 拦截器类
* @author gec
*
*/
@Aspect
public class MyInterceptor {
//1. 前置增强(XML配置)
@Before("execution(public * com.gec.spring.service.impl.*.*(..))")
public void before(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs(); //获取被拦截方法的参数列表
String methodName = joinPoint.getSignature().getName(); //被拦截方法的名称
Object target = joinPoint.getTarget(); //拦截的目标实例(业务类的实例)
//进一步完成功能 的增强
System.out.println("前置方法名:"+methodName+",参数列表:"+Arrays.toString(args)+",目标对象实例:"+target);
}
//2. 后置增强(XML配置)
@AfterReturning(pointcut="execution(public * com.gec.spring.service.impl.*.*(..))",returning="returnValue")
public void afterReturning(JoinPoint joinPoint,Object returnValue) {
Object[] args = joinPoint.getArgs(); //获取被拦截方法的参数列表
String methodName = joinPoint.getSignature().getName(); //被拦截方法的名称
Object target = joinPoint.getTarget(); //拦截的目标实例(业务类的实例)
//进一步完成功能 的增强
System.out.println("后置方法名:"+methodName+",参数列表:"+Arrays.toString(args)+",目标对象实例:"+target+",业务方法的返回值 :"+returnValue);
}
//3. 环绕增强
@Around("execution(public * com.gec.spring.service.impl.*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs(); //获取被拦截方法的参数列表
String methodName = pjp.getSignature().getName(); //被拦截方法的名称
Object target = pjp.getTarget(); //拦截的目标实例(业务类的实例)
System.out.println("环绕-前置方法名:"+methodName+",参数列表:"+Arrays.toString(args)+",目标对象实例:"+target);
Object returnValue = pjp.proceed(); //调用核心业务方法
System.out.println("环绕-后置方法名:"+methodName+",参数列表:"+Arrays.toString(args)+",目标对象实例:"+target+",业务方法的返回值 :"+returnValue);
return returnValue;
}
}
在配置文件启动注解配置
<bean id="myInterceptor" class="com.gec.spring.aop.MyInterceptor"></bean>
<!-- 启动aop的注解配置 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
spring中的事务管理
- 声明式事务:AOP
<!-- 配置声明式事务,官网的固定格式 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
<!-- 结合AOP实现事务的织入 -->
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务 -->
<!-- 配置事务的传播特性:new propagation -->
<tx:attributes>
<tx:method name="addUser" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入,在哪里使用事务 -->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
- 编程式事务:需要在代码中进行事务管理
为什么要配置事务?
如果不配置事务,可能会存在数据提交不一致的情况