JAVA后端框架【spring】--超详解
什么是spring?
spring是一个轻量级的ioc和Aop的一站式java开发框架,简化企业级开发
轻量级:框架体积小(核心模块)
IOC
IOC:inversion of control 控制反转 把创建对象的控制权反转给spring框架
AOP
Aop:面向切面编程
将程序中一些公共的非业务代码分离提取出来,然后在业务代码执行时,给他们横切进来
使用动态代理机制实现,我们的业务代码,不显示调用,但是执行业务代码,会通过代理对象,调用非业务代码
spring体系结构
搭建spring
1.Maven 导入 spring 核心基础 jar
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
2.编写 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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启spring注解扫描功能 指定扫描包-->
<context:component-scan base-package="com.wph.springpro"> </context:component-scan>
</beans>
-----------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!–
在spriing的配置文件注册需要spring管理的类
通过bean标签配置需要spring管理的类
id=“对象名称,可以再getBean中获得spring生成的对象”
class=“需要让spring管理的类的地址”
scope="配置bean的作用于"
scope="singleton"单例的(默认),在spring框架启动时,就创建对象,而且是这种只创建一个对象
scope="prototype"原型的(多例)在每次获得对象是,创建一个新的
IOC指的是让spring框架创建对象,创建对象的同时,还有一个动作称为依赖注入
依赖注入:在创建对象的时候,为对象中属性赋值
一来注入两种方式:
1.通过属性注入,属性的set方法
–>
<!– <bean id="user" class="com.wph.springpro.Model.User" scope="prototype">
<property name="account" value="admin"></property>
<property name="password" value="111"></property>
</bean>–>
<!–通过构造方法注入–>
<bean id="user" class="com.wph.springpro.Model.User" scope="prototype">
<constructor-arg name="account" value="admin"></constructor-arg>
<constructor-arg name="password" value="111"></constructor-arg>
</bean>
<bean id="AdminDao" class="com.wph.springpro.Dao.AdminDao"></bean>
<bean id="Adminservice" class="com.wph.springpro.Model.Adminservice">
<property name="adminDao" ref="AdminDao"></property>
</bean>
</beans>
3. 编写一个 User 实体类
package com.wph.springpro.Model;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component(value = "user")
@Scope(value = "prototype")
public class User {
private String account;
private String password;
public User() {
System.out.println("无参构造方法");
}
public User(String account, String password) {
this.account = account;
this.password = password;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
System.out.println("set");
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
System.out.println("setpassword");
this.password = password;
}
@Override
public String toString() {
return "User{" +
"account='" + account + '\'' +
", password='" + password + '\'' +
'}';
}
}
4.测试 spring
/*
ClassPathXmlApplicationContext是spring框架中的一个具体的实现类,负责生成,管理程序中对象
可以看做是一个容器,所以一般把spring框架也称为spring容器,或ioc容器
*
* 控制反转 这是一种编程思想
* 把对象生成的控制权,反转给spring框架,spring框架负责管理对象的整个生命周期
* 对外提供获取对象的方法,我们在程序中哪里需要,哪里获取就行
*
* */
public static void main(String[] args) {
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring.xml");
User user=(User) applicationContext.getBean("user");
User user1= applicationContext.getBean("user",User.class);
System.out.println(user);
System.out.println(user1);
}
IOC(控制反转)
读作“反转控制”(Inverse of Control)更好理解,不是什么技术,而是一种 设计思想,就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来 管理。
IOC 容器负责对象的实例化、对象的初始化,对象和对象之间依赖关系、 对象的销毁、对外提供对象的查找等操作,对象的整个生命周期都是由容器来 控制。
我们需要使用的对象都由 ioc 容器进行管理,不需要我们去手动通过 new 的方式去创建对象,由 ioc 容器直接帮我们组装好,当我们需要使用的时候直 接从 ioc 容器中直接获取就可以了。
正控:若要使用某个对象,需要自己去负责对象的创建
反控:若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象, 不关心对象的创建过程,也就是把创建对象的控制权反转给了 Spring 框架.
Spring Bean 管理
bean对象,由于把对象交给spring管理后,spring会对对象进行功能的增强,所以在spring框架中生成的对象,统一称为bean对象
基于 xml 配置方式
<!--
在spriing的配置文件注册需要spring管理的类
通过bean标签配置需要spring管理的类
id=“对象名称,可以再getBean中获得spring生成的对象”
class=“需要让spring管理的类的地址”
scope="配置bean的作用于"
scope="singleton"单例的(默认),在spring框架启动时,就创建对象,而且是这种只创建一个对象
scope="prototype"原型的(多例)在每次获得对象是,创建一个新的
IOC指的是让spring框架创建对象,创建对象的同时,还有一个动作称为依赖注入
依赖注入:在创建对象的时候,为对象中属性赋值
一来注入两种方式:
Xml 配置方式依赖注入
1.通过属性注入,属性的set方法
<bean id="user" class="com.wph.springpro.Model.User" scope="prototype">
<property name="account" value="admin"></property>
<property name="password" value="111"></property>
</bean>
2.通过构造方法注入
<bean id="user" class="com.wph.springpro.Model.User" scope="prototype">
<constructor-arg name="account" value="admin"></constructor-arg>
<constructor-arg name="password" value="111"></constructor-arg>
</bean>
注解方式实现
开启注解扫描 context:component-scan base-package="包名"> context:component-scan>
注解创建对象
@Component(value=“user”)等同于
@Service
@Repository
以上注解都可以实现创建对象功能,只是为了后续扩展功能,在不同的层使用不 同的注解标记 @Scope(value=“prototype”) 原型
@Scope(value=“ singleton ”) 单例
/*
sring注解方式bean管理 自动注入
@Autowired是spring框架提供的注解
用于在属性和属性的set方法上,如果写在属性上,set方法可以不需要
默认情况下要注入的值不能为空 required=true
自动注入有两种值的匹配方式
1.通过属性类型查找
2.通过对象的名字
@Qualifier(value = "adminDao")
@Repository 也是添加在属性上的,不需要添加set方法
注入的值不能为空的
也可以通过类型查找要注入的对象
也可以通过对象名字查找要注入的值 @Repository(value = "adminDao")
*/
@Autowired
//@Qualifier(value = "adminDao")
AdminDao adminDao;
public void save(){
adminDao.save();
adminDao.saveAdmin();
}
Spring 集成 Mybatis
Spring 集成 Mybatis 其核心是将 SqlSessionFactory 交由 Spring 管理,并由 Spring 管理对 dao 接口的代理实现。
1.导入 mybatis jar 包
<!--mybatis jar-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
2.配置 sqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis.xml"></property>
<property name="mapperLocations" value="classpath:Mappers/*Mapper.xml">
</property>
</bean>
3.指定生成接口代理
<bean id="mapperFactory" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wph.ssm.Dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">
</property>
</bean>
4.在 service 中注入 Dao 代理接口,此接口有 Spring 代理实现
@Service
public class LoginService {
@Autowired
LoginDao loginDao;
public Admin findaccount(Admin admin){
Admin admin1=loginDao.findAccount(admin);
return admin1;
}
}
======================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wph.ssm.Dao.LoginDao">
<select id="findAccount" parameterType="Admin" resultType="Admin">
select * from admin where account=#{account} and password=#{password}
</select>
</mapper>
========================================================================
public interface LoginDao {
Admin findAccount(Admin admin);
}
=======================================================================
public class te {
public static void main(String[] args) {
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");
LoginService loginService= applicationContext.getBean("loginService",LoginService.class);
Admin admin=new Admin();
admin.setAccount("admin");
admin.setPassword("111");
Admin admin1=loginService.findaccount(admin);
System.out.println(admin1);
}
}
注解与 XML 的对比
注解优点: 方便,直观,高效(代码少,没有配置文件的书写那么复杂)。
注解缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。
xml 优点是: 配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重 启服务器即可将新的配置加载。
xml 的缺点是:编写麻烦,效率低,大型项目过于复杂。
AOP
面向切面编程:面向对象编程的补充延续
面向切面编程思想:
将程序中一些公共的非业务代码(提交事务,打印日志,权限验证,统一异常处理)分离提取出来,然后在业务代码执行时,通过一个代理对象帮助我们调用这些提取出来的非业务代码,这样在业务代码不用显示调用非业务代码,做到业务代码和非业务代码分离,降低耦合度,给他们横切进来
使用动态代理机制实现,我们的业务代码,不显示调用,但是执行业务代码,会通过代理对象,调用非业务代码
原理:动态代理模式,给业务代码生成代理对象
AOP编程思想是java中的,不是spring专用的
是spring 使用AOP这一编程思想
连接点:类中可以被增强(加功能)的方法
切入点:类中实际被增强的方法
目标(target):代理目标类(连接点,切入点所在的类)
代理(proxy):向目标对象应用通知时创建的代理对象
通知:向连接点添加的功能
AOP 的基本概念
@Before 前置通知:业务方法执行之前 ,调用通知
@After 后置通知:业务方法执行之后,无论是否出现异常
@AfterReturnning 返回通知:方法成功执行之后通知,出现异常不执行
@AfterThrowing 异常通知:当业务代码出现异常时,抛出异常之后通知
@Around 环绕通知:方法执行前后都有通知 基于注解方式的实现
启动 AspectJ 支持:
<aop:aspectj-autoproxy />
@Component
@Aspect
public class communt {
// @Before("execution(* com.wph.springpro.Dao.AdminDao.*(..))")
// @After("execution(* com.wph.springpro.Dao.AdminDao.*(..))")
@AfterReturning("execution(* com.wph.springpro.Dao.*.*(..))")
public void printdiolg(){
System.out.println("打印日志");
}
@AfterThrowing(value = "execution(* com.wph.springpro.Dao.*.*(..))")
public void commit(){
System.out.println("提交事务");
}
/*
@Around 环绕通知 可以在业务方法执行之前,之后,出现异常时添加功能
ProceedingJoinPoint joinPoint 表示目标方法
*/
@Around(value = "execution(* com.wph.springpro.Dao.*.*(..))")
public void around(ProceedingJoinPoint joinPoint){
System.out.println("前置通知");
try {
Object object= joinPoint.proceed();//调用目标业务方法
System.out.println("返回通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知");
}
System.out.println("后置通知");
}
}
springAOP 实现
下载 AOP 相关 jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
Spring 事务管理
事务管理本质上是数据库提供的一种管理机制
数据库事务管理是对一次数据库操作过程中执行的多条语句进行管理,确保一次操作过程中的多条sql要么执行成功,要么都不执行,从而确保数据一致性
spring事务管理是spring框架对事物提交这一功能进行封装,程序员在业务开发中不需要的提交事务,sqlsession.commit()
1.编程式事务管理
需要程序员在代码中自己控制事务提交和回滚
2.声明式事务管理
声明事务底层使用了AOP思想,可以为方法添加事务功能,它的控制是方法级别的
@Transactional可以添加在方法上,也可以添加到类上面,如果添加到类上面,此类中所有的方法都在spring事务管理中进行
声明式事务失效场景:
1.@Transactional用在非public方法上
2.方法中的异常被捕获了,认为方法没有异常
3.方法中出现编译期异常,还是会提交事务
4.数据库引擎不支持事务 mysql中只有innodb引擎支持事务的
@Transactional
public void insert(){
String sql = "INSERT INTO admin (account, password) VALUES (?, ?)";
jdbcTemplate.update(sql, "zhangsan", "1111");
//System.out.println(10/0);
String sql1 = "INSERT INTO admin (account, password) VALUES (?, ?)";
jdbcTemplate.update(sql1, "lisi", "1111");
}
public void delete(){
System.out.println("删除");
} public void udate(){
System.out.println("修改");
}
配置事物管理器
<!-- 配置 spring 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
注解方式
<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
总结
为什么需要配置事务?
- 如果不配置,就需要我们手动提交控制事务;
- 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!