Spring

Spring

Spring:春天,给软件行业带来了春天。

2002年,首次推出了Spring的雏形: interface21 框架

Spring框架即以 interface21 框架为基础,经过重新设计,于2004年3月24日发布了1.0正式版

创始人:Rod Johnson 他是悉尼大学的博士,他不是计算机专业,而是音乐专业。

Spring理念:使现有的技术更加容易,本身是一个大杂烩,整合了现有的技术框架。

SSH:Struct2 + Spring + Hibernate

SSM : SpringMVC + Spring + Mybatis

​ Spring:是分层的java SE/EE 应用full-stack轻量级开源框架,以 IoC(反转控制) 和 AOP(面向切面编程)为内核。

优点:

  • Spring 是一个开源的免费的框架
  • Spring 是一个轻量级,非入侵式的框架
  • IoC(控制反转) 和 AOP(面向切面编程)
  • 支持事务的处理,对框架整合的支持

现代化的java开发,基于Spring的开发

Spring Boot:

一个快速开发的脚手架。

可以快速开发单个微服务。

Spring Cloud:

是基于Spring Boot 的实现。

弊端:

  • 发展太久后,违背了原来的理念,配置十分繁琐,“配置地狱”。

Spring 组成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rY1wTTWy-1690163368808)(Spring.assets/clip_image002.gif)]

Spring 作用
  • 控制反转 IOC
  • 依赖注入 DI
  • 面向切面 AOP
  • 对多个框架的整合
  • 降低代码的耦合 , 方便复用

IOC

IOC理念推导。

在我们之前的业务中,用户的需求可能会影响我们的源代码,如果一个程序代码量十分大,修改一次的成本代价十分昂贵。

使用 set 接口实现,已经发生了革命性的变化。

private UserDao userDao;
// 利用set进行动态实现值的注入
public void setUserDao(UserDao userDao){
    this.userDao = userDao;
}

之前:程序主动创建对象,控制权在程序猿手上。

现在:使用了 set 注入后,程序不在具有主动性,而变成了被动的接受对象。

我们不用再去管理对象的创建了,系统的耦合性大大降低,可以更加专注于业务的实现,这是loc的原型!

控制反转loc是一种设计思想,DI(依赖注入)是实现Ioc的一种方法。

-----------------------------------spring-study-01---------------------------------

Hello Spring

1.导入Spring

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

2.实现类

import lombok.*;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Hello {
    private String str;
}

3.ApplicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--使用Spring创建对象,在Spring中这些都称为bean
			id : 变量名  
   			 property :相当于给对象中的属性赋值
		-->
        <bean id="hello" class="com.zhang.pojo.Hello">
            <property name="str" value="Spring"/>    <!-- value :赋值 ref :引用Spring中创建好的对象 -->
        </bean>
</beans>

4.测试

public static void main(String[] args) {
        //获取spring上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //所有对象都在spring中管理,要使用直接取
		// Hello hello = (Hello) context.getBean("hello");  //hello :上面的id
        Hello hello = context.getBean("hello",Hello.class);  
    //Hello.class : 和上面一句代码作用一样(强转)
        System.out.println(hello.toString());
    }

// ---->  Hello(str=Spring)  

IOC创建对象的方式

  • 使用无参构造创建对象

  • 使用有参构造创建对象

    • 下标赋值

    • 通过参数名赋值

<!--下标赋值-->
<bean id="hello" class="com.zhang.pojo.Hello">
    <constructor-arg index="0" value="Spring"/>
</bean>
<!--通过参数名赋值-->
<bean id="hello" class="com.zhang.pojo.Hello">
    <constructor-arg name="str" value="Spring"/>
</bean>

在配置文件加载的时候,容器中管理的对象就已经初始化了

Spring配置

  • alias:别名
<alias name="user" alias="newUser"/>  
<!--如果添加了别名,我们使用别名也能获取到这个对象-->
  • Bean配置

    • id:bean的唯一标识符,相当于对象名
    • class:bean对象对应的全限定名:包名+类型
    • name:也是别名,可以取多个 (空格,逗号,分号都能分隔)
  • import

    一般用于团队开发使用,可将多个配置文件,导入合并为一个

<import resource="ApplicationContext.xml" />

-----------------------------------spring-study-02---------------------------------

DI 依赖注入

1. 构造器注入
2. set 注入

依赖:bean对象的创建依赖于容器

注入:bean对象中的所有属性由容器来注入

测试:

Student 实体类

package com.zhang.pojo;
import lombok.*;
import java.util.*;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
}

ApplicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

        <!--使用Spring创建对象,在Spring中这些都称为bean-->
        <bean id="address" class="com.zhang.pojo.Address">
                <property name="id" value="1"/>
                <property name="name" value="重庆"/>
        </bean>
        <bean id="student" class="com.zhang.pojo.Student">
                <!--普通值注入:value-->
                <property name="name" value="小灰灰"/>
                <!--bean注入 ref &ndash;&gt;对象-->
                <property name="address" ref="address"/>
			   <!--数组注入-->
                <property name="books">
                        <array>
                                <value>红楼梦</value>
                                <value>西游记</value>
                                <value>三国演义</value>
                                <value>水浒传</value>
                        </array>
                </property>
                <!--List注入-->
                <property name="hobbys">
                        <array>
                                <value>红楼梦</value>
                                <value>西游记</value>
                                <value>三国演义</value>
                                <value>水浒传</value>
                        </array>
                </property>
                <!--Map注入-->
                <property name="card">
                        <map>
                                <entry key="T123001" value="小灰灰"/>
                                <entry key="T123002" value="小黑黑"/>
                                <entry key="T123003" value="小李李"/>
                        </map>
                </property>
                <!--set注入-->
                <property name="games">
                        <set>
                                <value>红楼梦</value>
                                <value>西游记</value>
                                <value>三国演义</value>
                                <value>水浒传</value>
                        </set>
                </property>
                <!--null注入-->
                <property name="wife">
                        <null/>
                </property>
                <!--Properties注入-->
                <property name="info">
                        <props>
                                <prop key="T123001">455646563546</prop>
                                <prop key="T123002">546645656567</prop>
                                <prop key="T123003">456456546656</prop>
                        </props>
                </property>
        </bean>
</beans>

测试

public static void main(String[] args) {
    //获取spring上下文对象
    ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    //所有对象都在spring中管理,要使用直接取
    Student student = context.getBean("student", Student.class);
    System.out.println(student.toString());
}
3.p命名空间注入 c命名空间注入

User实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
}

ApplicationContext.xml

<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:c="http://www.springframework.org/schema/c"
       
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="pUser" class="com.zhang.pojo.User" p:name="zhang" p:age="19"/>
        <bean id="cUser" class="com.zhang.pojo.User" c:name="zhang" c:age="19"/>
</beans>

测试

public static void main(String[] args) {
        //获取spring上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    
       	//p命名空间
        User user = context.getBean("pUser", User.class);
        System.out.println(user.toString());
    
        //c命名空间
        User cUser = context.getBean("cUser", User.class);
        System.out.println(cUser.toString());
    }

Bean 作用域

  • singleton 单列模式(默认)

    不论get 几个,都是同一个对象

<bean id="address" class="com.zhang.pojo.Address" scope="singleton" />
  • prototype 原型模式

    每次从容器中get时,都会产生一个新对象

<bean id="address" class="com.zhang.pojo.Address" scope="prototype" />

  • request session application 只能在web开发中使用

-----------------------------------spring-study-03---------------------------------

Bean 的自动装配

自动装配是Spring满足bean依赖的一种方式

Spring 会在上下文中自动寻找,并自动给bean装配属性

Spring 中三种配置方式

  • xml 中显示配置
  • 在java中显示配置
  • 隐式的自动装配bean

实体

一个人有两个宠物

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Cat {
    private String name;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dog {
    private String name;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
    private String name;
    private Cat cat;
    private Dog dog;
}

byName 实现自动装配

ApplicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--使用Spring创建对象,在Spring中这些都称为bean-->
        <bean id="cat" class="com.zhang.pojo.Cat">
                <property name="name" value="小猫"/>
        </bean>
        <bean id="dog" class="com.zhang.pojo.Dog">
                <property name="name" value="小狗"/>
        </bean>
        <bean id="people" class="com.zhang.pojo.People" autowire="byName">
                <property name="name" value="小灰灰"/>
<!--                autowire="byName" 利用 自动装配 代替 下面两行代码 -->
<!--                <property name="cat" ref="cat"/>-->
<!--                <property name="dog" ref="dog"/>-->
        </bean>
</beans>

测试

@Test
public void testP(){
    //获取spring上下文对象
    ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    //所有对象都在spring中管理,要使用直接取
    People people = context.getBean("people", People.class);
    System.out.println(people.toString());
}

--->  People(name=小灰灰, cat=Cat(name=小猫), dog=Dog(name=小狗))
    

byType 实现自动装配

ApplicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--使用Spring创建对象,在Spring中这些都称为bean-->
        <bean id="cat" class="com.zhang.pojo.Cat">
                <property name="name" value="小猫"/>
        </bean>
        <bean id="dog" class="com.zhang.pojo.Dog">
                <property name="name" value="小狗"/>
        </bean>
        <bean id="people" class="com.zhang.pojo.People" autowire="byType">
                <property name="name" value="小灰灰"/>
        </bean>
</beans>

测试结果同上

注:

byName:保证所有bean的 id 唯一,并且bean需要和自动注入的属性的set方法值一致。

byType:保证所有bean的 class 唯一,并且bean需要和自动注入的属性的类型一致。

-----------------------------------spring-study-04---------------------------------

注解实现自动装配

1.导入约束

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd


2.配置注解的支持

<context:annotation-config/>

实体类

一个人有两个宠物

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Cat {
    private String name;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dog {
    private String name;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
    private String name;
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
}

ApplicationContext.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: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">
    	
        <context:annotation-config/>
    
    	<bean id="cat" class="com.zhang.pojo.Cat"/>
        <bean id="dog" class="com.zhang.pojo.Dog"/>
        <bean id="people" class="com.zhang.pojo.People"/>
</beans>

测试

@Autowired :自动装配(byName),直接在属性上使用,可以不写 set 方法

@Autowired(required = false) : 加上这个属性代表这个字段可以为null

@Nullable :字段标记了这个注解,说明这个字段可以为null

@Qualifier :如果自动装配环境复杂时

<bean id="dog" class="com.zhang.pojo.Dog"/>
<bean id="dog11" class="com.zhang.pojo.Dog"/>


@Autowired
private Dog dog;
@Autowired
@Qualifier(value = "dog11")
private Dog dog11;

@Resource 自动装配

<bean id="cat" class="com.zhang.pojo.Cat"/>

@Resource(name="cat")

@Autowired 和 @Resource

都是自动装配

@Autowired 通过 byName 的方式实现

@Resource 默认通过 byName ,如果找不到,通过 byType 实现

-----------------------------------spring-study-05---------------------------------

使用注解开发

在Spring4 之后,使用注解开发,必须要保证aop包的导入。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-epfXbkIg-1690163368809)(E:\预习\图片\QQ截图20210901110300.png)]

使用注解需要导入 Context 约束,增加注解支持。

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
        <context:annotation-config/>
</beans>

指定要扫描的包,这个包下的注解就会生效。

<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.zhang.pojo"/>


@Component : bean 注入

等价于:

<bean id="user" class="com.zhang.pojo.User"/>

@Component : 组件,放在类上,说明这个类被spring管理了,就是bean

@Value : 属性注入

等价于:

<property name="id" value="100" />

@Component
public class User {
    @Value("100")
    private int id;
    @Value("小灰灰")
    private String name;
}

@Component 有几个衍生的注解,在web开发中,会按照mvc三层架构分层。

@Repository  : dao

@Repository
public class userDao {
}


@Service : service

@Service
public class userService {
}


@Controller : servlet

@Controller
public class userServlet {
}


这四个注解都是一样的,都代表某个类注册到Spring中,装配Bean

@Scope(“singleton”) 作用域

prototype singleton request session

@Component
@Scope("singleton")
public class User {
    @Value("100")
    private int id;
    @Value("小灰灰")
    private String name;
}

xml 与 注解

xml : 更加万能,适用于任何场合,维护简单方便。

注解:不是自己的类使用不了,维护相对复杂。

xml 与 注解 最佳配置

xml 用来管理bean 注解只负责属性的注入

-----------------------------------spring-study-06---------------------------------

使用 java 的方式配置 Spring (纯注解的配置方式)

完全不使用Spring的xml配置

1.创建一个实体类(配置实体类)

@Configuration   // 被Spring容器托管,注册到容器中,代表应该配置类 和之前的ApplicationContext.xml一样
public class zhangConfig {
    @Bean   // 注册一个bean,就相当于之前写的一个bean标签
    public User getUser(){
        return new User();
    }
    // 方法的名字,及bean的id属性
    // 方法的返回值,及bean的class属性
}

User 实体类

@Data
@Component
public class User {
    @Value("小灰灰")
    private String name;
}

测试

@Test
public void testU(){
    ApplicationContext context = new AnnotationConfigApplicationContext(zhangConfig.class);
    User user = context.getBean("getUser",User.class);
    System.out.println(user.toString());
}

---> User(name=小灰灰)

如果完全使用配置类去做,就只能使用AnnotationConfig上下文来获取容器 通过配置类的class对象加载

代理模式

代理模式就是 Spring AOP 的底层

分类:

静态代理

动态代理

静态代理

抽象角色:一般会使用接口或抽象类来解决

真实角色:被代理的角色

代理角色:代理真实角色,代理后 一般会做一些附属操作

客户:访问代理对象的人

-----------------------------------spring-study-07---------------------------------

租房

/**
 * 抽象角色
 */
public interface Rent {
    public void rent();
}

/**
 * 真实角色
 * 房东
 */
public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租房子");
    }
}

/**
 * 代理角色
 * 中介
 */
public class Proxy implements Rent{
    private Host host;   //找到房东

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    @Override
    public void rent() {
        //帮助房东租房子 调用租房子的方法
        host.rent();
        //代理角色 还能做其他事(看房 收中介费...)
    }
}

测试

@Test
public void testJ(){
    Host host = new Host();  //房东
    //代理角色
    Proxy proxy = new Proxy(host);
    proxy.rent();   //代理角色帮助房东租房给客户
}

好处:

  • 可以使真实角色的操作更加纯粹
  • 公共业务就交给代理角色,实现了业务的分工
  • 公共业务发生拓展时 方便集中管理

缺点:

  • 一个真实角色就会产生一个代理角色,代码量会翻倍

动态代理

和静态代理角色一样。

代理类是动态生成的,不是直接写好的

分为两类:

基于接口:JDK动态代理

基于类:cglib

java字节码实现:javasist

需要了解:

Proxy:代理

InvocationHandler:调用处理程序

租房:

抽象角色 真实角色 同上

代理类

/**
 * 自动生成代理类
 * 工具类
 */
@Data
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;
    //生成代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }
    //处理代理实例 并返回结果
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        seeHouse();
        //动态代理的本质,就是反射机制实现
        Object result = method.invoke(target,objects);
        fare();
        return result;
    }
	
    //代理对象 带做的 
    public void seeHouse(){
        System.out.println("中介带去看房");
    }
	//代理对象 带做的
    public void fare(){
        System.out.println("收中介费");
    }
}


测试

@Test
public void testD(){
    //真实角色
    Host host = new Host();
    //代理角色
    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    //通过调用程序处理角色来处理要调用的接口对象
    pih.setTarget(host);
    Rent proxy = (Rent) pih.getProxy();    //proxy : 就是动态生成的 
    proxy.rent();
}

/*
中介带去看房
房东要出租房子
收中介费
*/

CRUD:添加日志

public interface userService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

public class userServiceImpl implements userService{
    @Override
    public void add() {
        System.out.println("添加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

调用工具类

/**
 * 自动生成代理类
 * 工具类
 */
@Data
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;
    //生成代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }
    //处理代理实例 并返回结果
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        log(method.getName()); // 添加日志功能
        //动态代理的本质,就是反射机制实现
        Object result = method.invoke(target,objects);
        return result;
    }

    public void log(String msg){
        System.out.println("执行了"+msg+"方法");
    }
}


@Test
public void testCRUD(){
    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    pih.setTarget(new userServiceImpl());
    userService us = (userService) pih.getProxy();
    us.add();
    us.delete();
    us.query();
    us.update();
}

/**
执行了add方法
添加了一个用户

执行了delete方法
删除了一个用户

执行了query方法
查询了一个用户

执行了update方法
修改了一个用户
*/

好处:

静态代理所有

一个动态代理类代理一个接口,一般就是对应一个类业务

一个动态代理类可代理多个类,只要实现同一个接口即可

-----------------------------------spring-study-08---------------------------------

AOP

面向切面编程

在spring中的作用。

提供声明式事物,允许用户自定义切面

  • 横切关注点:

跨越应用程序多个模型的方法或功能。即与业务逻辑无关的,但是需要关注的部分

如:日志 安全 缓存 事务

  • 切面(Aspect):横切关注点 被模块化 的特殊对象。即 它是一个类
  • 通知(Advice):切面必须要完成的工作 类中的一个方法
  • 目标(Target):被通知对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 切入点(PointCut):切面通知执行的“地点”的定义
  • 连接点(JointPoint):与切入点匹配的执行点

使用Aop 需要导入一个依赖包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>

CRUD : 添加日志

public interface userService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

public class userServiceImpl implements userService{
    @Override
    public void add() {
        System.out.println("添加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

方式一: 使用Spring Api 原生接口

前置日志

public class BeforeLog implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}

后置日志

public class AfterLog implements AfterReturningAdvice {
    //returnValue 返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了,返回值:"+returnValue);
    }
}

ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--        注册bean-->
        <bean id="userService" class="com.zhang.service.userServiceImpl"/>
        <bean id="afterLog" class="com.zhang.log.AfterLog"/>
        <bean id="beforeLog" class="com.zhang.log.BeforeLog"/>
<!--        方式一: 使用Spring Api 原生接口-->
<!--        配置bean 需要导入aop约束 -->
        <aop:config>
<!--                切入点   expression:表达式 execution(要执行的位置 * * * * *)-->
                <aop:pointcut id="pointcut" expression="execution(* com.zhang.service.userServiceImpl.*(..))"/>
<!--                执行环绕增加-->
                <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
                <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        </aop:config>

</beans>

测试

 @Test
public void MyTest(){
    ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    //动态代理代理的是接口
    userService us = context.getBean("userService", userService.class);
    us.add();
}

/**
    com.zhang.service.userServiceImpl的add被执行了
    添加了一个用户
    com.zhang.service.userServiceImpl的add被执行了,返回值:null
*/

方式二:使用自定义类

/**
 * 自定义类
 */
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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--        注册bean-->
        <bean id="userService" class="com.zhang.service.userServiceImpl"/>
        <!--方式二:自定义类    -->
        <bean id="diy" class="com.zhang.diy.diyPointCut"/>
        <aop:config>
<!--            自定义切面 ref 要引入的类 -->
            <aop:aspect ref="diy">
<!--                切入点-->
                <aop:pointcut id="point" expression="execution(* com.zhang.service.userServiceImpl.*(..))"/>
<!--                通知-->
                <aop:after method="after" pointcut-ref="point"/>
                <aop:before method="before" pointcut-ref="point"/>
            </aop:aspect>
        </aop:config>
</beans>

测试

 @Test
public void MyTest(){
    ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    //动态代理代理的是接口
    userService us = context.getBean("userService", userService.class);
    us.add();
}

/**
   	------前-----
    添加了一个用户
    ------后------
*/

-----------------------------------spring-study-09--------------------------------

方式三:使用注解实现

@Aspect
public class AnnotationPointCut {
    @Before("execution(* com.zhang.service.userServiceImpl.*(..))")
    public void before(){
        System.out.println("----------执行方法前--------");
    }
    @After("execution(* com.zhang.service.userServiceImpl.*(..))")
    public void after(){
        System.out.println("----------执行方法后-----------");
    }
    //执行环绕增强   ProceedingJoinPoint:获取处理切入的点
    @Around("execution(* com.zhang.service.userServiceImpl.*(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("执行环绕前");
        //获得签名
//        Signature signature = pjp.getSignature();
        //执行方法
        Object proceed = pjp.proceed();
        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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

        <bean id="userService" class="com.zhang.service.userServiceImpl"/>
        <bean id="annotationPointCut" class="com.zhang.Annotation.AnnotationPointCut"/>
<!--        开启注解的支持  JDK(默认 proxy-target-class="false") cglib(proxy-target-class="true")-->
        <aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>

测试

@Test
public void MyTest(){
    ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    //动态代理代理的是接口
    userService us = context.getBean("userService", userService.class);
    us.add();
}

/**
    执行环绕前
    ----------执行方法前--------
    添加了一个用户
    执行环绕后
    ----------执行方法后-----------
*/

-----------------------------------spring-study-10--------------------------------

整合 Mybatis-Spring

1.导入相关jar包

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    <!--Spring 操作数据库 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.7</version>
    </dependency>
    <!--mybatis spring 整合包-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>
</dependencies>

方式一: sqlSessionTemplate

查询所有

实体类

@Data
public class stuInfo {
    private String stu_id;
    private String stu_name;
    private String stu_sex;
    private int stu_age;
    private String stu_Address;
}

接口 实现类

public interface StuMapper {
    public List<stuInfo> selStuAll();
}

public class StuMapperImpl implements StuMapper{
    //原来 我们的所有操作但是使用sqlSession 来执行 现在 使用SqlSessionTemplate
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<stuInfo> selStuAll() {
        StuMapper mapper = sqlSession.getMapper(StuMapper.class);
        return mapper.selStuAll();
    }
}

mapper.xml

<?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">
<!--namespace Bind a corresponding Mapper interface-->
<mapper namespace="com.zhang.mapper.StuMapper">
    <!--select  resultType Entity classpath -->
    <select id="selStuAll" resultType="stuInfo">
        select * from stuInfo;
    </select>
</mapper>

mybatis-config.xml

<?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">
<!--Core configuration file configuration-->
<configuration>
    <!--别名-->
    <typeAliases>
        <package name="com.zhang.pojo"/>
    </typeAliases>
    <!--设置-->
<!--    <settings>-->
<!--        <setting name="" value=""/>-->
<!--    </settings>-->
</configuration>

spring-dao.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- DataSource 使用Spring 的配置源替换Mybatis的配置  使用Spring 提供的jdbc-->
    <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:3306/student?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT%2B8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!-- 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/zhang/mapper/*.xml"/>
    </bean>

<!--    SqlSessionTemplate 就是我们使用的sqlSession  -->
    <!--    方式二不用写 -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能使用构造器注入sqlSessionFactory 因为没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    
</beans> 

ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

        <import resource="spring-dao.xml"/>

        <bean id="stuMapper" class="com.zhang.mapper.StuMapperImpl">
                <property name="sqlSession" ref="sqlSessionTemplate"/>
        </bean>
</beans>

@Test
public void sel(){
    ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    StuMapper mapper = context.getBean("stuMapper",StuMapper.class);
    for (stuInfo stuInfo : mapper.selStuAll()) {
        System.out.println(stuInfo);
    }
}

/**
stuInfo(stu_id=T123001, stu_name=张秋丽, stu_sex=女, stu_age=18, stu_Address=沙坪坝)
stuInfo(stu_id=T123002, stu_name=李斯文, stu_sex=男, stu_age=19, stu_Address=沙坪坝)
stuInfo(stu_id=T123003, stu_name=李文才, stu_sex=女, stu_age=20, stu_Address=杨家坪)
*/

方式二: SqlSessionDaoSupport

实现类

public class StuMapperImplTwo extends SqlSessionDaoSupport implements StuMapper{

    @Override
    public List<stuInfo> selStuAll() {
        return getSqlSession().getMapper(StuMapper.class).selStuAll();
    }
}

ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

        <import resource="spring-dao.xml"/>

        <bean id="stuMapperTwo" class="com.zhang.mapper.StuMapperImplTwo">
                <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
</beans>

-----------------------------------spring-study-11--------------------------------

声明式事务

事务

  • 要么都成功,要么都失败
  • 事务在项目开发中,涉及数据的一致性问题
  • 确保完整性和一致性

事务ACID原则:

  • 原子性

  • 一致性

  • 隔离性

    多个业务可能操作同一个资源,复制数据损坏

  • 持久性

    事务一旦提交,无论发生什么问题,结果都不会发生影响,被持久化的写入储存器中

Spring中的事务管理

  • 声明式事务: AOP
  • 编程式事务:需要在代码中,进行事务管理

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StuInfo {
    private String stu_id;
    private String stu_name;
    private String stu_sex;
    private int stu_age;
    private String stu_Address;
}

接口 实现类

public interface StuMapper {
    public List<StuInfo> selStuAll();  //查询所有
    public int addStu(StuInfo stuInfo);
    public int delStu(String stu_id);
}

public class StuMapperImpl extends SqlSessionDaoSupport implements StuMapper{

    @Override
    public List<StuInfo> selStuAll() {
        StuMapper mapper = getSqlSession().getMapper(StuMapper.class);
        StuInfo stuInfo = new StuInfo("T123100","小灰灰","男",18,"重庆");
        mapper.addStu(stuInfo);    //添加
        mapper.delStu("T123100");  //删除
        return mapper.selStuAll();
    }

    @Override
    public int addStu(StuInfo stuInfo) {
        return getSqlSession().getMapper(StuMapper.class).addStu(stuInfo);
    }

    @Override
    public int delStu(String stu_id) {
        return getSqlSession().getMapper(StuMapper.class).delStu(stu_id);
    }
}

StuMapper.xml

<?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">
<!--namespace Bind a corresponding Mapper interface-->
<mapper namespace="com.zhang.mapper.StuMapper">
    <!--select  resultType Entity classpath -->
    <select id="selStuAll" resultType="stuInfo">
        select * from stuInfo;
    </select>

    <insert id="addStu" parameterType="stuInfo">
        insert into student.stuinfo(stu_id, stu_name, stu_sex, stu_age, stu_Address) VALUES (#{stu_id},#{stu_name}, #{stu_sex}, #{stu_age}, #{stu_Address});
    </insert>

    <delete id="delStu" parameterType="String">
        delete from student.stuinfo where stu_id = #{stu_id};
    </delete>

</mapper>

mybatis-config.xml

<?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">
<!--Core configuration file configuration-->
<configuration>
    <!-- -->
    <typeAliases>
        <package name="com.zhang.pojo"/>
    </typeAliases>
    <!--  -->
<!--    <settings>-->
<!--        <setting name="" value=""/>-->
<!--    </settings>-->
</configuration>

spring-dao.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- DataSource Use Spring configuration source to replace Mybatis configuration Use Spring provided jdbc-->
    <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:3306/student?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT%2B8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
    <!-- sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--Bind Mybatis configuration file-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/zhang/mapper/*.xml"/>
    </bean>
    
</beans>

ApplicationContext.xml

<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd">

        <import resource="spring-dao.xml"/>

        <bean id="stuMapper" class="com.zhang.mapper.StuMapperImpl">
                <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>

<!--        配置声明式事务-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"/>
        </bean>

        <!--结合AOP实现事务的织入-->
        <!--    配置事务通知    -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--                给那些方法配置事务-->
<!--                配置事务的传播特性 propagation -->
                <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.zhang.mapper.*.*(..))"/>
                <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
        </aop:config>
</beans>

注:

  • 如果不配置事务,可能存在数据提交不一致的情况
  • 如果不在SPRING中去配置声明式事务,我们就需要在代码中手动配置事务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值