Spring5学习
Spring-Study
代码:https://github.com/Donkequan/Spring-Study
1. 简介
spring理念:是现有的技术更加容易使用,本身是一个大杂烩。
- SSH:Struct2 + Spring + Hibernate
- SSM: SpringMVC + Spring + Mybatis
官网: https://spring.io/projects/spring-framework#overview
官方下载: https://repo.spring.io/release/org/springframework/spring/
GitHub: https://github.com/spring-projects/spring-framework
Spring Web MVC ? 5.2.5.RELEASE
org.springframework
spring-webmvc
5.2.5.RELEASE
org.springframework
spring-jdbc
5.2.3.RELEASE
- spring是开源的免费的容器。
- spring是一个轻量级的,非入侵式的。
- 控制反转(IOC),面向切面编程 (AOP)。
- 支持事务处理,对框架整合的支持。
总结:spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
2.IOC理论
-
UserDao
-
UserDaoImp
-
UserSevice
-
UserServiceImp
在之前,用户的需求可能会影响原来的代码。
使用一个set。
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
-
之前是主动创建对象,控制权在程序员手上。
-
使用set之后,是被动接受对象。
3. Hello Spring
pojo中
package com.hou.pojo;
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
resource种
<?xml version="1.0" encoding="UTF-8"?>
test
import com.hou.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
//获取spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象下能在都在spring·中管理了,我们要使用,直接取出来就可以了
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
bean = 对象
id = 变量名
class = new的对象
property 相当于给对象中的属性设值
核心用set注入
第一个文件中
<?xml version="1.0" encoding="UTF-8"?>
4. IOC创建对象的方式
- 使用无参构造创建对象,默认。
- 使用有参构造
下标赋值
<?xml version="1.0" encoding="UTF-8"?>
类型赋值(不建议使用)
直接通过参数名
Spring类似于婚介网站!
你想不想要,对象都在里面。注册bean之后用不用被实例化。
5. Spring配置
别名
Bean的配置
- id:bean的id标识符
- class:bean对象所对应的类型
- name:别名,更高级,可以同时取多个别名。
import
一般用于团队开发,它可以将多个配置文件,导入合并为一个
6. DI依赖注入
构造器注入
set方式注入(重点)
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
【环境搭建】
- 复杂类型
- 真实测试对象
package com.pojo;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List hobbies;
private Map card;
private Set game;
private Properties infor;
private String wife;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address +
", books=" + Arrays.toString(books) +
", hobbies=" + hobbies +
", card=" + card +
", game=" + game +
", infor=" + infor +
", wife='" + wife + '\'' +
'}';
}
}
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
三国
西游
水浒
eat
drink
play
wangzhe
daota
lol
20200405
hdk
第三方
p标签和c标签
package com.pojo;
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
<?xml version="1.0" encoding="UTF-8"?>
bean的作用域
- 单例模式(默认)
- 原型模式: 每次从容器中get的时候,都产生一个新对象!
- 其余的request、session、application这些只能在web开放中使用!
7. Bean的自动装配
- 自动装配是Spring是满足bean依赖的一种方式
- Spring会在上下文自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
-
在xml中显示配置
-
在java中显示配置
-
隐式的自动装配bean 【重要】
-
环境搭建:一个人有两个宠物
-
Byname自动装配:byname会自动查找,和自己对象set对应的值对应的id
保证所有id唯一,并且和set注入的值一致
-
Bytype自动装配:byType会自动查找,和自己对象属性相同的bean
保证所有的class唯一
public class Cat {
public void jiao(){
System.out.println("miao");
}
}
public class Dog {
public void jiao(){
System.out.println("wow");
}
}
package com.pojo;
public class People {
private Cat cat;
private Dog dog;
private String name;
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<?xml version="1.0" encoding="UTF-8"?>
使用注解自动装配
jdk1.5支持的注解,spring2.5支持的注解
The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML.
导入context约束
<?xml version="1.0" encoding="UTF-8"?>
@Autowire
在属性上个使用,也可以在set上使用
我们可以不用编写set方法了
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
}
@Nullable 字段标志的注解,说明这个字段可以为null
如果@Autowired自动装配环境比较复杂。自动装配无法通过一个注解完成的时候
我们可以使用@Qualifier(value = "dog")去配合使用,指定一个唯一的id对象
public class People {
@Autowired
private Cat cat;
@Autowired
@Qualifier(value = "dog")
private Dog dog;
private String name;
}
@Resource(name="dog")也可以
区别:
-
@autowire通过byType实现,而且必须要求这个对象存在
-
@resource默认通过byName实现,如果找不到,通过byType实现
8. 使用注解开发
在spring4之后,必须要保证aop的包导入
使用注解需要导入contex的约束
<?xml version="1.0" encoding="UTF-8"?>
- 属性如何注入
@Component
public class User {
@Value("dong")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 衍生的注解
@Component有几个衍生注解,会按照web开发中,mvc架构中分层。
- dao (@Repository)
- service(@Service)
- controller(@Controller)
这四个注解功能一样的,都是代表将某个类注册到容器中
- 作用域
@Scope("singleton")
@Component
@Scope("prototype")
public class User {
@Value("dong")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
小结:
xml与注解
- xml更加万能,维护简单
- 注解,不是自己的类,使用不了,维护复杂
最佳实践:
- xml用来管理bean
- 注解只用来完成属性的注入
<?xml version="1.0" encoding="UTF-8"?>
9. 使用java方式配置spring
JavaConfig
Spring的一个子项目,在spring4之后,,他成为了核心功能
@Configuration //这个也会被spring容器托管,注册到容器中,因为他本来就是一个@Component
@ComponentScan("com.pojo")
@Import(Config2.class)
public class MyConfig {
@Bean
public User getUser(){
return new User();
}
}
@Component
public class User {
@Value("dong")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
这种纯java配置方式
在springboot中,随处可见
10. 动态代理
动态代理和静态代理
角色一样
动态代理类是动态生成的,不是我们直接写好的!
动态代理:基于接口,基于类
- 基于接口:JDK的动态代理【使用】
- 基于类:cglib
- java字节码
InvocationHandler
Proxy
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//会这个类,自动生成代理类
public class ProxyInvocation implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object result = method.invoke(rent, args);
fare();
return result;
}
public void seeHouse(){
System.out.println("see house");
}
public void fare(){
System.out.println("fare");
}
}
public interface Rent {
void rent();
}
public class Host implements Rent {
public void rent() {
System.out.println("host rent");
}
}
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色
ProxyInvocation proxyInvocation = new ProxyInvocation();
//通过调用程序处理角色来处理我们要调用的接口对象
proxyInvocation.setRent(host);
Rent proxy = (Rent) proxyInvocation.getProxy(); //这里的proxy是动态生成的
proxy.rent();
}
}
11.AOP
org.aspectj
aspectjweaver
1.9.4
方法一:使用spring接口【springAPI接口实现】
<?xml version="1.0" encoding="UTF-8"?>
public class UserServiceImp implements UserService {
public void add() {
System.out.println("add");
}
public void delete() {
System.out.println("delete");
}
public void query() {
System.out.println("query");
}
public void update() {
System.out.println("update");
}
}
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//method:要执行的目标对象的方法
//args:参数
//target:目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+method.getName());
}
}
public class AfterLog implements AfterReturningAdvice {
//returnVaule: 返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+returnValue);
}
}
public class Mytest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplcationContext.xml");
//动态代理代理的是接口
UserService userService = (UserService) context.getBean("userservice");
userService.add();
}
}
方法二:自定义来实现AOP【主要是切面定义】
<?xml version="1.0" encoding="UTF-8"?>
public class DiyPointcut {
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
}
方法三:注解方式
<?xml version="1.0" encoding="UTF-8"?>
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect //标注这个类是一个切面
public class Annotation {
@Before("execution(* com.service.UserServiceImp.*(..))")
public void before(){
System.out.println("before");
}
@After("execution(* com.service.UserServiceImp.*(..))")
public void after(){
System.out.println("after");
}
//在环绕增强中,我们可以给地暖管一个参数,代表我们要获取切入的点
@Around("execution(* com.service.UserServiceImp.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around");
Object proceed = joinPoint.proceed();
System.out.println("after around");
}
}
12. 整合mybatis
文档: https://mybatis.org/spring/zh/
<?xml version="1.0" encoding="UTF-8"?>
spring-study
com.hou
1.0-SNAPSHOT
4.0.0
spring-10-mybatis
mysql
mysql-connector-java
5.1.47
org.mybatis
mybatis-spring
2.0.4
org.springframework
spring-jdbc
5.2.3.RELEASE
org.mybatis
mybatis
3.5.2
org.aspectj
aspectjweaver
1.9.4
org.projectlombok
lombok
1.18.12
src/main/resources
**/*.properties
**/*.xml
src/main/java
**/*.properties
**/*.xml
true
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8" ?>
public interface UserMapper {
List selectUser();
}
整合
方法一:
UserMapperImpl
package com.mapper;
import com.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
public List selectUser() {
UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
test
import com.mapper.UserMapper;
import com.pojo.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class Mytest {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
for (User user : userMapper.selectUser()) {
System.out.println(user);
}
}
}
方法二:
<?xml version="1.0" encoding="UTF-8"?>
package com.mapper;
import com.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperIml2 extends SqlSessionDaoSupport implements UserMapper {
public List selectUser() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
13. 声明式事务
- 要么都成功,要么都失败
- 十分重要,涉及到数据一致性
- 确保完整性和一致性
事务的acid原则:
-
原子性
-
一致性
-
隔离性
- 多个业务可能操作一个资源,防止数据损坏
-
持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会被影响。
Spring中的事务管理
- 声明式事务
- 编程式事务
声明式事务
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
Mapper
package com.mapper;
import com.pojo.User;
import java.util.List;
public interface UserMapper {
List selectUser();
int addUser(User user);
int delete(int id);
}
<?xml version="1.0" encoding="UTF-8" ?>
insert into mybatis.user (id, name, pwd) values
(#{id}, #{name}, #{pwd})
delete from mybatis.user where id=#{id}
package com.mapper;
import com.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperIml2 extends SqlSessionDaoSupport implements UserMapper {
public List selectUser() {
User user = new User(6, "long", "zhi");
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(user);
mapper.delete(6);
return mapper.selectUser();
}
public int addUser(User user) {
return getSqlSession().getMapper(UserMapper.class).addUser(user);
}
public int delete(int id) {
return getSqlSession().getMapper(UserMapper.class).delete(id);
}
}