# SpringStudy **Repository Path**: chmingx/spring-study ## Basic Information - **Project Name**: SpringStudy - **Description**: 学习Spring - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-05-18 - **Last Updated**: 2022-03-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Spring [TOC] ssm = springmvc + spring + mybatis ```xml org.springframework spring-webmvc 5.3.6 org.springframework spring-jdbc 5.3.6 ``` 优点: - 开源免费 - 轻量级,非入侵式框架 - 控制反转IOC - 面向切面编程AOP - 支持事务,对框架整合支持 组成: - AOP - ORM - DAO - Web - Context - MVC - Core Spring Boot 快速开发的脚手架,基于springboot可以快速开发单个微服务 Spring Cloud 基于Spring Boot实现的,集成的微服务 ## 1 IOC理论推导 ```java private UserDao userDao; // 通过set方法进行依赖注入,实现控制反转 // 之前,程序主动创建对象,控制权在程序员手中;现在主动性在用户手上,程序被动接收对象 public void setUserDao(UserDao userDao){ this.userDao = userDao; } ``` ==控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式. 在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入== 控制:由Spring创建对象,而不是程序本身;属性也由Spring设置 反转:程序本身不创建对象,被动接收对象 依赖注入:利用set方法进行注入 IOC: 一言以蔽之,对象由Spring来创建、管理、装配 什么事IOC: > 控制反转:把对象创建和对象之间的调用过程,交给Spring进行管理。能够降低耦合度 IOC底层原理: > xml解析、工厂模式、反射 ### 1.1 IOC 创建对象 1. 默认使用无参构造 ```xml ``` 2. 有参构造 ```xml ``` ## 2 依赖注入 依赖:bean对象的创建依赖于容器 注入:bean对象的属性由容器来注入 ### 2.1 构造器注入 ```xml ``` ### 2.2 set注入 ```xml ``` ### 2.3 扩展方式注入, C/P命名空间 ```xml ``` ### 2.4 特殊属性注入 ```xml 红楼梦 西游记 水浒传 三国演义 music movie reading LOL King 20200101001 male foobar ``` ## 3 Bean的作用域Scope - singleton 单例,对象是单一的,只有一个,默认 - prototype 原型,每次从容器中获取时都拿到一个新的对象,只不过属性与前面一致 ```xml ``` ## 4 Bean的自动装配 - 手动装配: - 在xml中显示的配置(见上面) - 自动装配: - 在xml中实现 - byName - byType - 在java中显示配置,通过注解 - @Autowired - @Resource ### 4.1 xml中实现自动装配 ```xml ``` ```xml ``` ### 4.2 在Java中通过注解实现 #### 4.2.1 @Autowired ```xml ``` - @Autowired, 自动装配,在属性或set方法上使用,可以不用编写set方法 - required - @Nullable, 可以为空, - @Qualifier, 指定bean对象进行注入 ```java public class Person { private String name; // 如果显示标注了required为false,则这个属性可以为空 @Autowired(required = false) private Cat cat; @Autowired @Qualifier("dog") // 指定名称,用于处理变量名与属性名不一致的情况 private Dog dog; @Nullable private String name; // name可以为空 } ``` #### 4.2.2 @Resource - Resource, 自动装配,会先匹配名称,再匹配类型 ```java public class Person { private String name; // java自带注解 @Resource private Cat cat; @Resource(name="dog") private Dog dog; } ``` ## 5 使用注解开发 不需要再xml中编写bean了,直接注解生成bean ```xml ``` - @Component, 这个类被Spring管理了,用于类 - @Repository/@Mapper, Component的引申注解,效果等同于Component, 通常用于Spring的DAO - @Service - @Controller - @Value, 为属性添加默认值, 用于属性或set方法 - @Scope, 为类设置作用域,@Scope("singleton"), 设置为单例, 等同于在 `beans.xml`中设置 `` - singleton - prototype ```java // @Component注解等价于 , 就是说在容器中注入这样一个对象 @Component @Scope("singleton") public class User { @Value("foobar") // 等价于 private String name; @Autowired private Cat cat; } ``` 一般,用xml管理bean,用注解注入属性 ## 6 使用Java进行配置 xml都不用了, 直接再Java中进行配置 ```java public class User { @Value("foobar") private String name; @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ``` ```java @Configuration public class AppConfig { // // 方法名相当于bean中的id // 返回值类型相当于bean中的class @Bean public User user() { return new User(); } } ``` AppConfig等同于下面的xml ```xml ``` ```java public class UserTest { @Test public void test() { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); User user = context.getBean("user", User.class); System.out.println(user); } } ``` ## 7 代理模式 扩展被代理对象的功能 - 静态代理 - 动态代理 ### 7.1 静态代理 ```java // 抽象成员 interface BuyHouse{ public void buy(); } ``` ```java // 被代理对像 class BuyHouseImpl implement BuyHouse{ @Override public void buy(){ System.out.println("buy a house"); } } ``` ```java // 代理对象 class BuyHouseProxy implement BuyHouse{ private BuyHouse buyHouse; public BuyHouseProxy(BuyHouse buyHouse){ this.buyHouse = buyHouse; } @Override public void buy(){ System.out.println("看房"); buyHouse.buy(); System.out.println("收中介费"); } } ``` ```java // 客户端 class Client{ public static void main(String[] args){ BuyHouse buyHouse = new BuyHouseImpl(); BuyHouseProxy proxy = new BuyHouseProxy(buyHouse); proxy.buy(); } } ``` ### 7.2 动态代理 Proxy: 生成动态代理 InvocationHandler: 调用处理程序并返回结果 ```java public interface BuyHouse { public void buy(); } ``` ```java package org.example.dynamic; public class BuyHouseImpl implements BuyHouse{ @Override public void buy() { System.out.println("buy house"); } } ``` ```java package org.example.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 动态代理调用处理器 */ public class DynamicProxyHandler implements InvocationHandler { // 被代理的接口 private Object object; public DynamicProxyHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Begin-----------------"); Object invoke = method.invoke(object, args); // 利用反射调用类里面的方法 System.out.println("After-----------------"); return invoke; // invoke 为调用结果,如果没有则为null } } ``` ```java package org.example.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { BuyHouse buyHouse = new BuyHouseImpl(); // 创建调用处理器 InvocationHandler invocationHandler = new DynamicProxyHandler(buyHouse); // 动态创建代理对象 BuyHouse proxyInstance = (BuyHouse) Proxy.newProxyInstance( invocationHandler.getClass().getClassLoader(), // 代理类的类加载器 buyHouse.getClass().getInterfaces(), // 被代理类的接口 invocationHandler // 代理调用处理器 ); proxyInstance.buy(); } } ``` ## 8 AOP 面向切面编程 ![](images/aop.png) 本质是动态代理 ```xml org.aspectj aspectjweaver 1.9.4 ``` ### 8.1 使用Spring的切片API来实现切片 - 编写切面 ```java public class BeforeLog implements MethodBeforeAdvice { /** * * @param method 要执行的目标对象,或被代理对象的方法 * @param objects 参数 * @param o 目标对象 * @throws Throwable */ @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("执行" + method.getName() + " ..."); } } ``` ```java public class AfterLog implements AfterReturningAdvice { /** * * @param o 方法返回值 * @param method 要执行的目标对象,或被代理对象的方法 * @param objects 参数 * @param o1 目标对象 * @throws Throwable */ @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println(method.getName() + "结束,结果为:" + o); } } ``` - 定义切入点,进行切入 ```xml ``` - 测试 ```java public class UserServiceTest { @Test public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = context.getBean("userService", UserService.class); userService.select(); } } ``` ### 8.2 自定义类实现切片 - 使用自定义切片 ```java package org.example.diyPointCut; // 自定义切片类 public class DIYPointCut { public void before() { System.out.println("before ..."); } public void after() { System.out.println("after ..."); } } ``` - 定义切入点,进行切入 ```xml ``` ### 8.3 使用注解实现切片 - 使用注解实现切片 ```java package org.example.diyPointCut; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class AnnotationPointCut { @Before("execution(* org.example.service.UserServiceImpl.*(..))") public void before() { System.out.println("=======before=============="); } @After("execution(* org.example.service.UserServiceImpl.*(..))") public void after() { System.out.println("=======after=============="); } // 在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点 @Around("execution(* org.example.service.UserServiceImpl.*(..))") public void aroud(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕前..."); Signature signature = joinPoint.getSignature(); System.out.println("signature:" + signature); Object proceed = joinPoint.proceed(); System.out.println("环绕后..."); } } ``` ```xml ``` ### 8.4 切点表达式 Advice主要类型: - @Before - @After - @AfterReturning - @AfterThrowing - @Around - @Pointcut 设置切入点 ```java //设置切点为delete方法 @Pointcut(value = "execution(* com.maoge.demo1.User.delete(..))") private void myPointcut() {} @Before(value = "myPointcut()") public void UserCheck1() { System.out.println("用户校验1"); } @AfterThrowing(value = "myPointcut()") public void UserCheck2() { System.out.println("用户校验2"); } @AfterReturning(value = "myPointcut()") public void UserCheck3() { System.out.println("用户校验3"); } ``` PCD:pointcut designators - within 筛选出某包下的所有类 - execution execution(注解?修饰符?返回值类型 类型声明?方法名(参数)异常?) - @within表示匹配带有指定注解的类 - @annotation 匹配有指定注解的方法(注解作用在方法上面) ```java execution(修饰符匹配式? 返回类型匹配式 类名匹配式? 方法名匹配式(参数匹配式) 异常匹配式?) execution(* com.xyz.service..*.*(..)): 匹配com.xyz.service及其子包下的任意方法 within(com.xyz.service.*)com.xyz.service包下的类,不包括子包 @within(com.spring.annotation.BusinessAspect) ``` PCD之间支持,`&& || !`三种运算符。上文示例中就使用了&& 运算符。`||`表示或(不是短路或)。`!`表示非。 ## 9 整合mybatis - 导入依赖 ```xml org.mybatis mybatis-spring 2.0.2 ``` - 编写spring-dao.xml配置, 使用Spring的DataSource替换Mybatis配置 ```xml ``` ```xml ``` - 在spring-dao中配置SqlSessionFactory ```xml ``` - 编写接口及实现类 ```java package org.example.mapper; import org.apache.ibatis.annotations.Param; import org.example.pojo.User; public interface UserMapper { User getUserById(@Param("id") int id); } ``` ```java package org.example.dao; import org.example.pojo.User; import org.mybatis.spring.SqlSessionTemplate; public class UserMapperImpl implements UserMapper { private SqlSessionTemplate sqlSessionTemplate; @Override public User getUserById(int id) { UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class); return userMapper.getUserById(id); } public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = sqlSessionTemplate; } } ``` - 编写mapper.xml ```xml ``` - 添加SqlSessionTemplate, 注入SqlSessionFactory生产SqlSessionTemplate ```xml ``` - 注入SqlSessionTemplate生产Mapper ```xml ``` - 测试 ```java public class UserMapperTest { @Test public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); System.out.println(userMapper.getUserById(2)); } } ``` 方法二,不在配置中显示生成SqlSessionTemplate,使用SqlSessionDaoSupport - 实现类需继承SqlSessionDaoSupport ```java public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper { @Override public User getUserById(int id) { return getSqlSession().getMapper(UserMapper.class).getUserById(id); } } ``` - 配置UserMapper的bean ```xml ``` - 测试 ```java public class UserMapperTest { @Test public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); System.out.println(userMapper.getUserById(2)); } } ``` ## 10 事务 ACID: 原子性、一致性、隔离性、持久性 Spring中事务: - [x] 声明式事务:交给容器管理事务,是AOP - [ ] 编程式事务:需要在代码中进行事务管理 ### 10.1 声明式事务 - 配置声明式事务 ```xml ``` - 导入约束 ```xml ``` - 结合AOP实现事务的织入 ```xml ``` - 配置事务切入 ```xml ``` - 测试 ```java @Test public void testTransaction() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); for (User user : userMapper.getAllUser()) { System.out.println(user); } userMapper.addUser(new User(3, "ww", "456789")); userMapper.deleteUser(4); for (User user : userMapper.getAllUser()) { System.out.println(user); } } ``` ## 11 MVC MVC是模型视图控制器的简写,是将业务逻辑、数据、显示分离的方法来组织代码。能降低试图与业务逻辑间的双向耦合 SpringMVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架, 就是servlet - 轻量级 - 高效 - 与Spring无缝结合 - 约定优于配置 - 功能强大RESTful,数据验证,本地化,格式化 SpringMVC围绕DispatherServlet设计。DispatherServlet的作用是将请求分别发送到不同处理器 ## 12 Json json是JavaScript对象的字符串表示法,它使用文本表示一个JavaScript对象,本质是一个字符串 ```javascript var obj = {a: 'Hello', b: 100} var json = '{"a": "Hello", "b": 100}' ``` ```xml com.fasterxml.jackson.core jackson-databind 2.10.0 com.alibaba fastjson 1.2.60 ```