Spring
依赖
<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>
优点
- 轻量级、非入侵式(不会对已有的项目造成影响)
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理 支持多框架的整合
IOC控制反转
由原本把对象的创建和对象间的依赖方式写死,变为把对象的创建交给第三方决定,这就是控制反转
配置
配置文件
<!--在resources文件夹下创建beans.xml文件-->
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
</beans>
对象是Spring创建的,对象的属性值是Spring容器设置的
需求 需要方便满足用户的要求
<!--在resources文件夹下创建beans.xml文件-->
<?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">
<bean id="aUser" class="com.rush.po.User">
<property name="id" value="1"/>
<property name="username" value="mc"/>
</bean>
<bean id="UserDaoImpl" class="com.rush.dao.UserDaoImpl"/>
<bean id="UserDaoMysqlImpl" class="com.rush.dao.UserDaoMysqlImpl"/>
<bean id="UserDaoOracleImpl" class="com.rush.dao.UserDaoOracleImpl"/>
<!--传入Oracle的实现对象 以后需要修改直接改beans文件即可-->
<bean id="UserServiceImpl" class="com.rush.service.UserServiceImpl">
<property name="userDao" ref="UserDaoOracleImpl"/>
</bean>
</beans>
别名
<alias name="user" alias="userNew"/>
<!--多个别名 1 2 3 4都是user2的别名-->
<alias name="user2" alias="userNew,1 2;3,4"/>
import
把多个beans.xml合并为一个
<?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">
<import resource="beans.xml"/>
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
</beans>
依赖注入
构造器注入
<bean id="UserServiceImpl" class="com.rush.service.UserServiceImpl">
<property name="userDao" ref="UserDaoOracleImpl"/>
</bean>
set注入
<bean id="teachcer" class="com.rush.po.Teacher">
<bean id="student" class="com.rush.po.Student">
<!--set普通注入-->
<property name="name" value="rush"/>
<!--Bean注入引用对象-->
<property name="teacher" value="teacher"/>
<!--数组注入-->
<property name="books">
<array>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
<!--list注入-->
<property name="hobbys">
<list>
<value>歌曲</value>
<value>游戏</value>
</list>
</property>
<!--Map-->
<property name="car">
<map>
<entry key="" value=""/>
</map>
</property>
<!--Set-->
<property>
<set>
<value>LOL</value>
<value>WOW</value>
</set>
</property>
<!--空值-->
<property name="wife">
<null/>
</property>
<!--properties-->
<property name="info">
<props>
<prop key="学号">311900xxxx</prop>
<prop key="姓名">rush</prop>
</props>
</property>
</bean>
空间注入
- p:set注入
- c:构造器注入
<!--p 先加约束 xmlns:p="http://www.springframework.org/schema/p"-->
<bean id="user" class="com.rush.po.User" p:name="rush" p:age="18"/>
<!--c 先加约束 xmlns:p="http://www.springframework.org/schema/c"-->
<!--需要无参和有参构造器-->
<bean id="user" class="com.rush.po.User" c:name="rush" c:age="18"/>
作用域
单例
Spring默认使用
<bean id="user" class="com.rush.po.User" c:name="rush" c:age="18" scope="singleton"/>
原型
每次都是一个新对象
<bean id="user" class="com.rush.po.User" c:name="rush" c:age="18" scope="prototype"/>
剩余
- request
- session
- application
- websocket
Bean自动装配
byName
id要和实体类一样才能找到
<bean id="cat" class="com.rush.po.Cat"/>
<bean id="dog" class="com.rush.po.Dog"/>
<!--把cat和dog对象自动放入有dog和cat的People实体类对象中-->
<bean id="People" class="com.rush.po.People" autowire="byName"/>
byType
对应的类型必须全局唯一
<bean id="cat1" class="com.rush.po.Cat"/>
<bean id="dog1" class="com.rush.po.Dog"/>
<!--把cat和dog对象自动放入有dog和cat的People实体类对象中-->
<bean id="People" class="com.rush.po.People" autowire="byType"/>
注解自动装配
@Autowired先找type再找name
@Autowired(required = false)//设置required的值使得属性可以为空 否则为空会报异常
@Qualifier(value="dogRush") //手动设置对应的xml中的name
private Cat cat;
导入约束
<?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
http://www.springframework.org/schema/context/spring-context.xsd"
<context:annotation-config/>
</beans>
>
@Resource注解
//先找name再找type
@Resource
private Cat cat;
@Resource(name = "dogdog")
private Dog dog;
注解开发
先导入aop
<!--打开包扫描-->
<context:component-scan base-package=""/>
装配类并注入值
@Component
public class User{
@Value("rush")
public String name;
}
衍生的注解
功能与@Componet相同
- Dao:@Repository
- Service:@service
- controller:Controller
@Scope,类似配置文件中的scope,可设置使用单例模式、原型模式等
注解与xml配合
一般用xml注册类,注解赋值
Java配置类
JavaConfig是Spring的一个子项目,在Spring4之后成为了一个核心功能。
//配置类
package com.rush.config;
import com.rush.po.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @author:zmc
* @function:
* @date: 2020/8/2 11:30
*/
@Component
public class Config {
@Bean
public User getUser(){
return new User();
}
}
//实体类
package com.rush.po;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
/**
* @author:zmc
* @function:
* @date: 2020/8/1 10:35
*/
@Data
public class User {
@Value("666")
private int id;
@Value("弟弟")
private String username;
}
//测试类
package com.rush;
import com.rush.config.Config;
import com.rush.po.User;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author:zmc
* @function:
* @date: 2020/8/1 10:43
*/
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext config
= new AnnotationConfigApplicationContext(Config.class);
User user = (User) config.getBean("getUser");
System.out.println(user);
}
}
这种纯Java,不使用xml的模式就是SpringBoot的模式。
AOP
面试必问AOP和SpringMVC
底层:代理模式
AOP就是横向开发 不改变原有代码
原生态实现AOP
使用原生态的Spring API接口
运行前增强
package com.rush.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
* @author:zmc
* @function:
* @date: 2020/8/2 14:17
*/
public class Log implements MethodBeforeAdvice {
/**
*
* @param method 要被执行的方法
* @param args 参数
* @param target 目标对象
* @throws Throwable
*/
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
运行后增强
package com.rush.log;
import org.springframework.aop.AfterAdvice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
/**
* @author:zmc
* @function:
* @date: 2020/8/2 14:27
*/
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,执行结果为:"+returnValue);
}
}
原接口
package com.rush.service;
import com.rush.dao.UserDao;
import com.rush.dao.UserDaoImpl;
import com.rush.po.User;
import org.springframework.context.annotation.Scope;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* @author:zmc
* @function:
* @date: 2020/8/1 11:18
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加了一个用户");
}
}
切入点配置
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
<bean id="userService" class="com.rush.service.UserServiceImpl"/>
<bean id="log" class="com.rush.log.Log"/>
<bean id="after" class="com.rush.log.AfterLog"/>
<aop:config>
<!--第一个*表示返回的类型 *表示所有类型-->
<!--包名-->
<aop:pointcut id="pointcut" expression="execution(* com.rush.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="after" pointcut-ref="pointcut"/>
</aop:config>
</beans>
测试类
package com.rush;
import com.rush.config.Config;
import com.rush.po.User;
import com.rush.service.UserService;
import com.rush.service.UserServiceImpl;
import org.aspectj.apache.bcel.util.ClassPath;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author:zmc
* @function:
* @date: 2020/8/1 10:43
*/
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//动态代理代理的是接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
自定义类实现AOP
自定义类
package com.rush;
/**
* @author:zmc
* @function:
* @date: 2020/8/2 14:55
*/
public class DiyPointCut {
public void before(){
System.out.println("--------------方法执行前--------------");
}
public void after(){
System.out.println("--------------方法执行后--------------");
}
}
切面配置
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
<bean id="diy" class="com.rush.DiyPointCut"/>
<bean id="userService" class="com.rush.service.UserServiceImpl"/>
<aop:config>
<!--自定义切面-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression=
"execution(* com.rush.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
测试类
package com.rush;
import com.rush.config.Config;
import com.rush.po.User;
import com.rush.service.UserService;
import com.rush.service.UserServiceImpl;
import org.aspectj.apache.bcel.util.ClassPath;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author:zmc
* @function:
* @date: 2020/8/1 10:43
*/
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//动态代理代理的是接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
注解实现AOP
切面类
package com.rush;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* @author:zmc
* @function:
* @date: 2020/8/2 15:09
*/
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.rush.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("--------方法执行前--------");
}
@After("execution(* com.rush.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("--------方法执行后--------");
}
@Around("execution(* com.rush.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp){
System.out.println("--------环绕前--------");
Signature signature = jp.getSignature();
System.out.println(signature);
try {
jp.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("--------环绕后--------");
}
}
配置注解
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
<bean id="annotationPointCut" class="com.rush.AnnotationPointCut"/>
<bean id="userService" class="com.rush.service.UserServiceImpl"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
</beans>
Spring Aop 默认使用JDK实现 可以改为cglib
<!--默认为false 即JDK 改为true即cglib-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
整合Mybatis
SqlSessionTemplate需要使用构造器注入,因为没有set方法。
编写数据源 sqlSession
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--用Spring的数据源代替Mybatis的配置-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/mybatis?
useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--配置原来Mybatis的sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定Mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/rush/mapper/*.xml"/>
</bean>
<!--SqlSessionTemplate就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<bean id="userMapper" class="com.rush.mapper.UserMapperImpl">
<property name="sqlSessionTemplate" ref="sqlSession"/>
</bean>
</beans>
加实现类
package com.rush.mapper;
import com.rush.po.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
/**
* @author:zmc
* @function:
* @date: 2020/8/2 23:08
*/
public class UserMapperImpl implements UserMapper
{
private SqlSessionTemplate sqlSession;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
Mybatis扫描包
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.rush.po"/>
</typeAliases>
</configuration>
Mapper配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rush.mapper.UserMapper">
<select id="selectUser" resultType="user">
select * from mybatis.user
</select>
</mapper>
测试类
package com.rush;
import com.rush.mapper.UserMapper;
import com.rush.po.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author:zmc
* @function:
* @date: 2020/8/2 22:59
*/
public class test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
for (User user : userMapper.selectUser()) {
System.out.println(user);
}
}
}
继承SqlSessionDaoSupport
精简了原本的实现类
package com.rush.mapper;
import com.rush.po.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
/**
* @author:zmc
* @function:
* @date: 2020/8/3 11:08
*/
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> selectUser() {
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
}
写完记得去Spring配置文件
<!--可省略sqlSessionTemplate-->
<bean id="userMapper2" class="com.rush.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
声明式事务
- 把一组业务当作一个业务来做,要么都成功,要么都失败
- 事务在实际开发中非常重要
事务ACID原则
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
- 原子性:要么同时成功,要么同时失败
- 一致性:事务开始之前和结束之后,关系数据的完整性和业务逻辑的一致性
A给B转账 A和B的存款总数是不会变化的
- 隔离性:要防止多个事务同时操作一个资源时数据错误
- 持久性:事务一旦提交,数据就会被持久化地写入存储器,不会再改变
配置
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!--配置事务通知-->
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--配置事务传播特性-->
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<!--配置切入面-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.rush.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
注意
导入tx依赖时 idea会出错 需要修改
xmlns:tx="http://www.springframework.org/schema/cache"
<!--改为下面这个才行-->
xmlns:tx="http://www.springframework.org/schema/tx"
Spring七大传播属性
- REQUIRED:支持当前事务,如果没有事务,就新建一个事务。一般使用这个
- SUPPORTS:支持当前事务,如果没有事务,就以非事务方式执行
- MANDATORY:支持当前事务,如果没有事务,就抛出异常
- REQUIRES_NEW:新建事务,如果已存在事务,则将当前事务挂起
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则将当前事务挂起
- NEVER:以非事务方式执行,如果已存在事务,则抛出异常
- NESTED:支持当前事务,如果已存在事务,则执行一个嵌套事务,如果没有事务,则新建事务。