Spring学习笔记

1 spring介绍

1)为什么学习spring

​ 1. Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%

​ 2. 简化开发,降低企业级开发的复杂性

​ 3. 框架整合,高效整合其他技术,提高企业级应用开发与运行效率

​ 作为一个java程序员, spring必学., 是必经之路!

2)spring框架学什么?

​ 1. IOC

​ 2. AOP

​ 3. 整合

3)spring中的设计模式

​ 学习spring的, 先了解下spring中主要的设计模式:

1. 工厂模式

​ 1.简单工厂

​ 简单工厂模式是一种创建型设计模式,用于根据给定的类型实例化不同的类

​ 例如: 不同的动物类型创建对应的动物实例。

public interface Animal {void speak();
}
public class Dog implements Animal {@Overridepublic void speak() {System.out.println("Woof!");}
}public class Cat implements Animal {@Overridepublic void speak() {System.out.println("Meow");}
}

然后,创建一个名为AnimalFactory的简单工厂类,它负责根据给定的类型实例化相应的动物实例:

public class AnimalFactory {public enum AnimalType {DOG,CAT}public static Animal createAnimal(AnimalType type) {switch (type) {case DOG:return new Dog();case CAT:return new Cat();default:throw new IllegalArgumentException("Invalid animal type: " + type);}}
}

最后,我们可以在主方法中使用这个简单工厂类来创建不同类型的动物实例:

public class Main {public static void main(String[] args) {Animal dog = AnimalFactory.createAnimal(AnimalFactory.AnimalType.DOG);dog.speak();Animal cat = AnimalFactory.createAnimal(AnimalFactory.AnimalType.CAT);cat.speak();}
}

​ 2.抽象工厂

​ 抽象工厂模式是一种创建型设计模式,它允许您根据不同的族系或者平台来实例化一组相关的对象;

​ 首先,我们定义两个接口,AnimalPlant

public interface Animal {void speak();
}public interface Plant {void grow();
}

接下来,为不同族系创建具体的AnimalPlant实现:

// 陆地生物
public class LandAnimal implements Animal {@Overridepublic void speak() {System.out.println("I am a land animal.");}
}public class LandPlant implements Plant {@Overridepublic void grow() {System.out.println("I am a land plant.");}
}// 水生生物
public class AquaticAnimal implements Animal {@Overridepublic void speak() {System.out.println("I am an aquatic animal.");}
}public class AquaticPlant implements Plant {@Overridepublic void grow() {System.out.println("I am an aquatic plant.");}
}

然后,创建一个名为NatureFactory的抽象工厂接口:

public interface NatureFactory {Animal createAnimal();Plant createPlant();
}

接着,为不同族系创建具体的工厂实现:

public class LandFactory implements NatureFactory {@Overridepublic Animal createAnimal() {return new LandAnimal();}@Overridepublic Plant createPlant() {return new LandPlant();}
}public class AquaticFactory implements NatureFactory {@Overridepublic Animal createAnimal() {return new AquaticAnimal();}@Overridepublic Plant createPlant() {return new AquaticPlant();}
}

最后,在主方法中,我们可以使用这些抽象工厂类来创建不同族系的AnimalPlant实例:

public class Main {public static void main(String[] args) {NatureFactory landFactory = new LandFactory();Animal landAnimal = landFactory.createAnimal();Plant landPlant = landFactory.createPlant();landAnimal.speak();landPlant.grow();NatureFactory aquaticFactory = new AquaticFactory();Animal aquaticAnimal = aquaticFactory.createAnimal();Plant aquaticPlant = aquaticFactory.createPlant();aquaticAnimal.speak();aquaticPlant.grow();}
}

通过使用抽象工厂模式,您可以轻松地在不同的族系之间切换,同时保持代码的可扩展性和封装

2.单例模式

​ 1.饿汉式(可用)

​ 饿汉式单例模式是一种创建型设计模式,它在类加载时就创建了对象实例,并确保只有一个实例存在.

public class Singleton {// 在类加载时创建唯一的实例private static final Singleton INSTANCE = new Singleton();// 将构造方法设为私有,防止外部创建新实例private Singleton() {}// 提供获取唯一实例的公共方法public static Singleton getInstance() {return INSTANCE;}
}
public class Main {public static void main(String[] args) {Singleton singletonInstance = Singleton.getInstance();}
}

饿汉式单例模式在类加载时就创建了实例,这意味着即使您从未使用过该实例,它也会占用内存。这可能导致资源浪费,特别是在实例创建成本较高的情况下.

​ 2.懒汉式(不可用,线程不安全)

​ 懒汉式单例模式是一种创建型设计模式,它在第一次请求实例时才创建唯一的实例,并确保整个应用程序中仅存在一个实例.

public class Singleton {// 初始化唯一实例为空private static Singleton instance = null;// 将构造方法设为私有,防止外部创建新实例private Singleton() {}// 提供获取唯一实例的公共方法public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

​ 3.懒汉式(锁方法, 不推荐使用)

​ 同上, 在创建对象的静态方法上加上同步锁synchronized .

​ 4.双重检查(推荐使用)

​ 双重检查锁定(Double-Checked Locking,DCL)是一种用于确保在多线程环境下懒汉式单例模式的线程安全性的方法.

public class Singleton {// 使用volatile关键字确保内存可见性private static volatile Singleton instance = null;// 将构造方法设为私有,防止外部创建新实例private Singleton() {}// 提供获取唯一实例的公共方法,并使用双重检查锁定public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

​ 首先,我们进行第一次检查:如果instance为空,说明实例尚未创建,此时需要获取Singleton.class的锁。当线程成功获得锁后,进行第二次检查:确保在其他线程获得锁之前实例仍未被创建。如果instance仍然为空,则创建新的实例;否则,直接返回已创建的实例。

​ 此实现在多线程环境中是线程安全的,并且相对于每次都获取锁的懒汉式单例模式具有更好的性能

​ 5.静态内部类(推荐使用)

public class Singleton {// 将构造方法设为私有,防止外部创建新实例private Singleton() {}// 静态内部类负责创建唯一实例private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}// 提供获取唯一实例的公共方法public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}			

当Singleton类加载时, 由于静态内部类在外部内加载时并不会加载, 而时在静态内部内调用时才加载, 所以该方法并不会像饿汉式那样浪费资源, 同时Java规范保证了静态初始化是线程安全的,因此在类加载时会创建唯一的实例, 所以次方法比较推荐;

​ 6.枚举(推荐使用)

public enum Singleton {INSTANCE;// 可以添加其他方法和属性public void doSomething() {System.out.println("Singleton enum is doing something");}
}
public class Main {public static void main(String[] args) {Singleton singletonInstance = Singleton.INSTANCE;singletonInstance.doSomething();}
}

使用枚举实现单例模式是一种简洁且安全的方法。在Java中,枚举类型可以确保线程安全和实例唯一性;

3.代理模式

​ 代理模式是一种结构型设计模式,其目的是通过代理来控制对实际对象的访问。代理通常与实际对象具有相同的接口,并将请求转发给实际对象,可能会在转发之前或之后执行其他操作;

public interface Subject {void operation();
}
public class RealSubject implements Subject {@Overridepublic void operation() {System.out.println("RealSubject is performing the operation");}
}
public class ProxySubject implements Subject {private final RealSubject realSubject;public ProxySubject(RealSubject realSubject) {this.realSubject = realSubject;}@Overridepublic void operation() {preOperation();realSubject.operation();postOperation();}private void preOperation() {System.out.println("Executing pre-operation tasks in proxy");}private void postOperation() {System.out.println("Executing post-operation tasks in proxy");}
}
public class Main {public static void main(String[] args) {RealSubject realSubject = new RealSubject();ProxySubject proxySubject = new ProxySubject(realSubject);// 使用代理执行操作,它将执行预/后操作并调用RealSubject的operation()proxySubject.operation();}
}

在实际应用中,代理模式可以被用于实现许多功能,例如安全性检查、日志记录、缓存和远程访问等.

4)了解Spring大家族

​ Spring发展到今天已经形成了一种开发的生态圈,Spring提供了若干个项目,每个项目用于完成特定的功能;官网: Spring | Home

1.spring framework

​ 也就是我们经常说的spring框架,主要分为IOC和AOP两大块;

2.spring boot

​ 它的目标是简化Spring应用和服务的创建、开发与部署,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用的微服务功能,可以和spring cloud联合部署。

​ Spring Boot的核心思想是约定大于配置,应用只需要很少的配置即可,简化了应用开发模式。

3.Spring Data

​ 是一个数据访问及操作的工具集,封装了多种数据源的操作能力,包括:jdbc、Redis、MongoDB等

4.Spring Cloud

​ 是一套完整的微服务解决方案,是一系列不同功能的微服务框架的集合

5. Spring Security

​ 主要用于快速构建安全的应用程序和服务, 负责进行应用程序的认证, 授权;

5)spring framework组成

​ spring框架分为两大块, IOC和AOP;

​ spring框架包含一下几大模块:

image

1、 Core Container(核心容器)

​ Beans模块:提供了BeanFactory,是工厂模式的经典实现,Spring将管理对象称为Bean。

​ Core核心模块:提供了Spring框架的基本组成部分,包括IoC和DI功能。

​ Context上下文模块:建立在Core和Beans模块的基础之上,它是访问定义和配置的任何对象的媒介。

​ SpEL模块:它提供了Spring Expression Language支持,是运行时查询和操作对象图的强大的表达式语言

2、Data Access/Integration(数据访问/集成)

​ JDBC模块:提供了一个JDBC的抽象层,大幅度地减少了在开发过程中对数据库操作的编码。

​ ORM模块:对流行的对象关系映射API,包括JPA、JDO和Hibernate提供了集成层支持。

​ OXM模块:提供了一个支持对象/ XML映射的抽象层实现,如JAXB、Castor、XMLBeans、JiBX和XStream。

​ JMS 模块:指 Java 消息传递服务,包含使用和产生信息的特性,自 4.1 版本后支持与Spring-message模块的集成。

​ Transactions事务模块:支持对实现特殊接口以及所有POJO类的编程和声明式的事务管理。

3、 Web

​ WebSocket模块:Spring 4.0以后新增的模块,它提供了WebSocket 和SockJS的实现,以及对STOMP的支持。

​ Servlet模块:也称为Spring-webmvc模块,包含了Spring的模型—视图—控制器(MVC)和REST Web Services实现的Web应用程序。

​ Web模块:提供了基本的Web开发集成特性,例如:多文件上传功能、使用Servlet监听器来初始化IoC容器以及Web应用上下文。

​ Portlet模块:提供了在Portlet环境中使用MVC实现,类似Servlet模块的功能。

4、 其他模块

​ AOP 模块:提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按照功能进行分离,以降低耦合性。

​ Aspects 模块:提供了与AspectJ的集成功能,AspectJ是一个功能强大且成熟的面向切面编程(AOP)框架。

​ Instrumentation 模块:提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。

​ Messaging模块:Spring 4.0以后新增的模块,它提供了对消息传递体系结构和协议的支持。

​ Test模块:提供了对单元测试和集成测试的支持

2 IoC和DI

1)IoC介绍和使用

​ IoC(Inversion of Control)控制反转, 它将对象之间的依赖关系与对象本身的创建和管理分离开来。这有助于降低程序中各个组件之间的耦合度,并提高代码可维护性、可测试性以及扩展性。

​ 在Spring IoC容器中,对象的生命周期由容器进行管理,而不是由对象自己管理。IoC容器负责实例化、配置和装配Bean,然后将这些Bean注入到需要的组件中。使用IoC可以使您专注于业务逻辑的实现,而不必关心底层的对象创建和依赖解析工作。

​ Spring IoC容器主要包括两种类型:

​ 1.BeanFactory:BeanFactory是一个简单的容器,它负责实例化、定位、配置应用程序中的对象,并解决它们之间的依赖关系。XmlBeanFactory是最常用的BeanFactory实现。

​ 2.ApplicationContext:ApplicationContext是BeanFactory的子接口,它为应用程序提供了更多的企业级特性,如消息资源处理、事件发布、声明式事务处理等。通常,我们会使用ApplicationContext作为Spring IoC容器,常见的实现有ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等

IOC简单示例

导入jar;

image

public interface GreetingService {void sayHello();
}		
public class Student {public void sayHello() {System.out.println("Hello, Spring IoC!");}
}
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="student" class="com.qs.spring.Student"></bean></beans>
public static void main(String[] args) {// 加载Spring配置文件ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 获取Bean并使用sayHello()方法Student student = (Student) context.getBean("student");student.sayHello();
}

bean的作用范围

<bean class="com.qs.spring.entity.Student" scope="prototype"><property name="sid" value="1001"></property><property name="sname" value="张三"></property><property name="gender" value=""></property>
</bean>

当scope为prototype, 是多例;为singleton或者默认都是单例;

bean的生命周期

  1. 实例化:Spring根据配置文件或注解定义创建Bean实例。
  2. 属性填充:Spring通过依赖注入将指定的属性值和引用设置到Bean的属性中,这可以是基于构造方法、setter方法或字段的注入。
  3. 容器回调(Aware接口):如果Bean实现了某些特定的Aware接口(如BeanNameAware、BeanFactoryAware等),Spring会自动调用相应的回调方法,将容器相关的信息传递给Bean。
  4. BeanPostProcessor前置处理:Spring会调用已注册的所有BeanPostProcessor接口实现类的postProcessBeforeInitialization方法,允许您进行自定义处理,例如修改Bean属性或改变Bean引用。
  5. 初始化:当Bean的所有属性都设置好后,Spring会检查Bean是否实现了InitializingBean接口,如果实现了该接口,Spring会调用afterPropertiesSet()方法。此外,如果Bean定义中包含init-method属性(XML配置)或@PostConstruct注解(注解配置),也会执行对应的初始化方法。
  6. BeanPostProcessor后置处理:Spring会调用已注册的所有BeanPostProcessor接口实现类的postProcessAfterInitialization方法,同样允许您进行自定义处理。
  7. Bean准备就绪:至此,Bean已经准备好了,可以被应用程序使用。
  8. 销毁:当容器关闭时,Spring会检查Bean是否实现了DisposableBean接口,如果实现了该接口,Spring会调用destroy()方法。此外,如果Bean定义中包含destroy-method属性(XML配置)或@PreDestroy注解(注解配置),也会执行对应的销毁方法。

注意:在整个生命周期中,BeanPostProcessor前置/后置处理和Aware接口回调等特性可以通过编程方式自定义,以满足具体需求。

2)DI的介绍和使用

​ 依赖注入(Dependency Injection,DI)是Spring框架的核心概念之一。它是一种将组件之间的依赖关系从组件内部移除的设计模式,使得组件之间的耦合度降低,代码更加灵活和可维护.

​ 在Spring框架中,DI通过控制反转(Inversion of Control,IoC)容器实现。IoC容器负责管理应用程序中的对象(称为Bean)以及它们之间的依赖关系。简单来说,DI允许我们将对象的创建和配置委托给IoC容器,并在需要时将这些对象注入其它对象.

​ Spring提供了以下几种主要的依赖注入方式:

  1. 基于构造函数的注入:通过构造函数将依赖项传递给需要它们的类。在XML配置中,使用<constructor-arg>元素实现;而在基于注解的配置中,可以在构造函数上添加@Autowired注解。
  2. 基于Setter方法的注入:通过调用setter方法将依赖项传递给需要它们的类。在XML配置中,使用<property>元素实现;而在基于注解的配置中,可以在setter方法上添加@Autowired注解。
  3. 基于字段的注入:直接向类的字段注入依赖项,而无需使用构造函数或setter方法。在基于注解的配置中,可以在字段上添加@Autowired注解。

基于构造函数的注入:

​ 导入jar;

image

​ 需要进行注入的实体类;

public class Student {private  Integer sid;private  String sname;private  String gender;public Student(Integer sid, String sname, String gender) {this.sid = sid;this.sname = sname;this.gender = gender;}
}

​ xml文件中构造注入:

<bean class="com.qs.spring.entity.Student" id="student"><constructor-arg name="gender" value=""></constructor-arg><constructor-arg name="sid" value="1001"></constructor-arg><constructor-arg name="sname" value="张三"></constructor-arg>
</bean>

基于Setter方法的注入:

public class Student {private  Integer sid;private  String sname;private  String gender;public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}
<bean class="com.qs.spring.entity.Student"><property name="sid" value="1001"></property><property name="sname" value="张三"></property><property name="gender" value="男"></property>
</bean>

​ 属性值为对象的注入:

public class Student {......private Clazz clazz;public Clazz getClazz() {return clazz;}public void setClazz(Clazz clazz) {this.clazz = clazz;}......
}	
	<bean class="com.qs.spring.entity.Student"><property name="sid" value="1001"></property><property name="sname" value="张三"></property><property name="gender" value=""></property><property name="clazz" ref="clazz"></property></bean><bean class="com.qs.spring.entity.Clazz" id="clazz"><property name="cid" value="1001"></property><property name="cname" value="DT117"></property></bean>

​ 自动注入: 当需要注入的值是对象并且IOC容器中也存在该对象时, 可以选择自动注入: autowire;

byType: 根据类型自动注入;

byName: 根据id的值和属性名称自动注入;

<bean class="com.qs.spring.entity.Student" autowire="byType"><property name="sid" value="1001"></property><property name="sname" value="张三"></property><property name="gender" value=""></property>
</bean>
<bean class="com.qs.spring.entity.Clazz" id="clazz"><property name="cid" value="1001"></property><property name="cname" value="DT117"></property>
</bean>

​ 属性值为数组, 集合等注入:

public class Student {......private List<Integer> list;private Set<Integer> set;private Map<String,String> map;public List<Integer> getList() {return list;}public void setList(List<Integer> list) {this.list = list;}public Set<Integer> getSet() {return set;}public void setSet(Set<Integer> set) {this.set = set;}public Map<String, String> getMap() {return map;}public void setMap(Map<String, String> map) {this.map = map;}......
}	
<bean class="com.qs.spring.entity.Student" autowire="byName"><property name="sid" value="1001"></property><property name="sname" value="张三"></property><property name="gender" value=""></property><property name="list"><list><value>111</value><value>222</value><value>333</value></list></property><property name="set"><set><value>444</value><value>555</value><value>666</value></set></property><property name="map"><map><entry key="aaa" value="123"></entry><entry key="bbb" value="111"></entry><entry key="ccc" value="321"></entry></map></property></bean>

基于字段的注入

​ 直接在需要注入的属性上添加注解实现;

@Autowired
private Clazz clazz;

​ @Autowired: 在IoC容器中根据类型查找, 然后注入到指定的属性中;

​ @Resource: 该注解并非Spring注解, 而是java中的注解,作用和 @Autowired类似, 是在根据名称进行注入;

3 Aop

​ Spring AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架的一个重要特性,它允许将与业务逻辑无关的横切关注点(如日志记录、安全检查、事务管理等)从应用程序代码中分离出来。这有助于提高代码的模块化程度,使得应用程序更加易于维护和扩展。

​ 在Spring AOP中,主要涉及以下几个核心概念:

  1. 切面(Aspect):封装了横切关注点的模块化代码,通常包含一个或多个通知(Advice)以及切入点(Pointcut)的定义。
  2. 通知(Advice):切面在特定连接点执行的操作。根据执行时机不同,通知可以分为前置通知(Before)、后置通知(After)、返回通知(After-returning)、异常通知(After-throwing)和环绕通知(Around)。
  3. 切入点(Pointcut):描述了通知应该织入的一系列连接点。切入点通过类和方法签名的模式匹配定义,例如匹配特定包下所有类的所有方法。
  4. 连接点(Join point):程序执行过程中可以插入切面操作的点,例如方法调用、构造函数调用、字段赋值等。Spring AOP仅支持方法执行连接点。
  5. 引入(Introduction):允许为现有类添加新方法或属性的一种方式。
  6. 织入(Weaving):将切面与目标对象组合在一起,创建代理对象的过程。织入可以在编译时、类加载时或运行时完成。Spring AOP默认使用运行时织入。

1)使用配置文件实现:

​ 导入jar;

image

​ 创建业务类接口:

public interface GoodsService {void sayHello(String name);
}

​ 实现接口:

public class GoodsServiceImpl implements GoodsService {@Overridepublic void sayHello(String name) {System.out.println("Hello, " + name);}
}

​ 创建增强处理的类和方法:

public class myLogger {//JoinPoint  可以获取到业务方法的相关的信息//前置通知public void beforeLogging(JoinPoint point){System.out.println("------------------------------进入前置通知---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);System.out.println(".------------------------------离开前置通知---------------------");}//后置通知public void afterLogging(JoinPoint point,Object result){System.out.println("------------------------------进入后置通知---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);System.out.println("---------------------返回值:"+result);System.out.println(".------------------------------离开后置通知---------------------");}//环绕通知public Object aroundLogging(ProceedingJoinPoint point) throws Throwable {System.out.println("------------------------------进入环绕通知---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);//手动执行业务方法  并且接收返回值Object result = point.proceed();System.out.println("---------------------返回值:"+result);System.out.println(".------------------------------离开环绕通知---------------------");return result;}   //异常通知public void execptionLogging(JoinPoint point,Exception e){System.out.println("------------------------------进入异常通知---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);System.out.println("---------------------发生了异常:"+e.getMessage());System.out.println(".------------------------------离开异常通知---------------------");}//最终通知public void finallyLogging(JoinPoint point){System.out.println("------------------------------进入最终通知---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);System.out.println(".------------------------------离开最终通知---------------------");}
}    
	<bean class="com.qs.spring.service.GoodsService"></bean>	<bean class="com.qs.spring.aop.MyLogger" id="myLogger"></bean><aop:config><aop:pointcut id="pt" expression="execution(* com.qs.spring.service.*.*(..))"/><aop:aspect ref="myLogger"><aop:before method="beforeLogging" pointcut-ref="pt"></aop:before><aop:after-returning method="afterLogging" pointcut-ref="pt" returning="result"></aop:after-returning><aop:around method="aroundLogging" pointcut-ref="pt"></aop:around><aop:after-throwing method="execptionLogging" pointcut-ref="pt" throwing="e"></aop:after-throwing><aop:after method="finallyLogging" pointcut-ref="pt"></aop:after></aop:aspect></aop:config>   

2)使用注解实现:

​ 1) 给创建增强处理的类和方法加上指定的注解:

​ @Aspect: 用在增加处理类上,声明该类为aop的一个切面类;

​ @Pointcut(“execution(* cn.guotu.service..(…))”), 用在方法上, 指定一个切入点

​ @Before(), 用在方法上, 代表该方法是一个前置增强方法

​ @Around(), 用在方法上, 代表该方法是一个环绕增强方法

​ @AfterReturning(), 用在方法上, 代表该方法是一个后置增强方法

​ @AfterThrowing(), 用在方法上, 代表该方法是一个异常增强方法

​ @After(), 用在方法上, 代表该方法是一个异常增强方法

@Aspect
public class MyLoggerAspacj {//切入点@Pointcut("execution(* cn.guotu.service.*.*(..))")public void pt(){}@Before("pt()")public void beforeLogging(JoinPoint point){System.out.println("------------------------------进入前置增强---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);System.out.println(".------------------------------离开前置增强---------------------");}//环绕增强@Around("pt()")public Object aroundLogging(ProceedingJoinPoint point) throws Throwable {System.out.println("------------------------------进入环绕增强---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);//手动执行业务方法  并且接收返回值Object result = point.proceed();System.out.println("---------------------返回值:"+result);System.out.println(".------------------------------离开环绕增强---------------------");return result;}@AfterReturning(pointcut = "pt()",returning="result")public void afterLogging(JoinPoint point,Object result){System.out.println("------------------------------进入后置增强---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);System.out.println("---------------------返回值:"+result);System.out.println(".------------------------------离开后置增强---------------------");}//异常增强@AfterThrowing(pointcut = "pt()",throwing = "e")public void execptionLogging(JoinPoint point,Exception e){System.out.println("------------------------------进入异常增强---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);System.out.println("---------------------发生了异常:"+e.getMessage());System.out.println(".------------------------------离开异常增强---------------------");}@After("pt()")public void finallyLogging(JoinPoint point){System.out.println("------------------------------进入最终增强---------------------");System.out.println("---------------------进入了类:"+point.getTarget().getClass().getName());System.out.println("---------------------进入了方法:"+point.getSignature().getName());System.out.println("---------------------传入了参数:"+point.getArgs()[0]);System.out.println(".------------------------------离开最终增强---------------------");}
}
<bean class="com.qs.spring.service.GoodsService"></bean>	
<bean class="com.qs.spring.aop.MyLogger" id="myLogger"></bean><!--打开aop的注解扫描-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>	

3 spring整合mybatis

​ 1)添加jar

image

​ 2) 创建配置文件:

image

datasources.propertiesurl=jdbc:mysql://127.0.0.1:3306/goods?serverTimezone=Asia/Shanghai
driver=com.mysql.cj.jdbc.Driver
user=root
password=root
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">
<configuration><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin></plugins>
</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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsd"><!--加载db.properties--><context:property-placeholder location="db.properties"/><!--配置连接环境--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="password" value="${password}"></property><property name="username" value="${user}"></property><property name="url" value="${url}"></property><property name="driverClassName" value="${driver}"></property></bean><!--  sqlsessionfactory  --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property><property name="configLocation" value="mybatis-config.xml"></property></bean><!--配置mapper扫描的包--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="cn.guotu.mapper"></property></bean>
</beans>
spting-service.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"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"><!--开启service包的扫描--><context:component-scan base-package="cn.guotu.service"></context:component-scan>
</beans>

实体类: Goods.java(略)

Mapper接口: GoodsMapper.java(略)

服务层: GoodsService.java(略)

4 spring事务管理

1)基于配置文件的事务

当在service的业务方法中, 对数据库有1个以上的操作时, 如果方法内任何一个地方出现异常, 那么对数据的所有操作都需要回滚, 要么全部都执行成功, 要么都执行后失败!

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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"><!--开启service包的扫描--><context:component-scan base-package="cn.guotu.service"></context:component-scan><!-- 配置事务管理器 (增强处理类) --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!-- 配置哪些方法需要进行事务管理  (切入点)--><tx:advice id="advice" transaction-manager="transactionManager"><tx:attributes><tx:method name="insert*" propagation="REQUIRED"/><tx:method name="save*" propagation="REQUIRED"/><tx:method name="add*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="change*" propagation="REQUIRED"/><tx:method name="delete*" propagation="REQUIRED"/></tx:attributes></tx:advice><aop:config><aop:pointcut id="pt" expression="execution(* cn.guotu.service.*.*(..))"/><aop:advisor pointcut-ref="pt" advice-ref="advice"></aop:advisor></aop:config>
</beans>
GoodsService.javapublic void insert(){Goods goods = new Goods();goods.setGname("国土1");goods.setGcount(100);goods.setGprice(5.6);goods.setCreateTime(new Date());goods.setTid(1);int i =  goodsMapper.insert(goods);int a = 10/0;Goods goods1 = new Goods();goods1.setGname("国土2");goods1.setGcount(100);goods1.setGprice(5.6);goods1.setCreateTime(new Date());goods1.setTid(1);int i1 =  goodsMapper.insert(goods1);System.out.println(i1);}

2)基于注解实现事务

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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"><!--开启service包的扫描--><context:component-scan base-package="cn.guotu.service"></context:component-scan><!-- 配置事务管理器 (增强处理类) --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!-- 开始事务的注解扫描 --><tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven></beans>
GoodsService.java@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.SERIALIZABLE)
public void insert(){Goods goods = new Goods();goods.setGname("国土1");goods.setGcount(100);goods.setGprice(5.6);goods.setCreateTime(new Date());goods.setTid(1);int i =  goodsMapper.insert(goods);int a = 10/0;Goods goods1 = new Goods();goods1.setGname("国土2");goods1.setGcount(100);goods1.setGprice(5.6);goods1.setCreateTime(new Date());goods1.setTid(1);int i1 =  goodsMapper.insert(goods1);System.out.println(i1);
}

3)事务的传播机制

​ Propagation:

1.REQUIRED

如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的默认设置。

image

调用methdoA,如果methodB发生异常,触发事务回滚,也会methodA中的也会回滚

2.SUPPORTS

支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。

image

如果调用methodA,再调用methodB,MehtodB会加入到MethodA的开启的当前事务中。  如果直接调用methodB,当前没有事务,就以非事务执行。  

3.MNDATORY

支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

image

如果调用methodA,再调用methodB,MehtodB会加入到MethodA的开启的当前事务中。  如果直接调用methodB,当前没有事务,就会抛出异常。  

4.REQUIRES_NEW

创建新事务,无论当前存不存在事务,都创建新事务。

image

调用methodA,会先开启事务1,执行A的something pre的代码。再调用methodB,methdoB会开启一个事务2,再执行自身的代码。最后在执行methodA的something post。如果method发生异常回滚,只是methodB中的代码回滚,不影响methodA中的代码。如果methodA发生异常回滚,只回滚methodA中的代码,不影响methodB中的代码。  

5.NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

image

调用methodA,再调用methodB,methodA开启的事务会被挂起,即在methodB中不齐作用,相当于没有事务,methodB内部抛出异常不会回滚。methodA内的代码发生异常会回滚。 直接调用methodB,不会开启事务。

6.NEVER

以非事务方式执行操作,如果当前存在事务,则抛出异常。

image

7.NESTED

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

image

调用methodA,开启一个事务,执行something pre的代码,设置回滚点savepoint,再调用methodB的代码,如果methodB里抛出异常,此时回滚到之前的saveponint。再然后执行methodA里的something post的代码,最后提交或者回滚事务。 嵌套事务,外层的事务如果回滚,会导致内层的事务也回滚;但是内层的事务如果回滚,仅仅是回滚自己的代码,不影响外层的事务的代码。

4)事务的隔离级别

1) 读未提交(脏读) (不加任何锁)
​ 当一个事务开启后, 修改了数据, 但是未提交事务之前, 另外一个事务来读取数据, 可以读到未提交的数据;
​ 由于读的数据是未提交的, 那么万一事务回滚, 数据就读到的是错的; 会产生脏数据;

2)读提交(不可重复读) (写锁(部分行))
​ 如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据,该隔离级别避免了脏读,但是可能出现不可重复读。事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变

3)可重复读(读写锁(部分行))
​ 可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写),这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别;
​ 读取数据的事务将会禁止写事务,写事务则禁止任何其他事务(包括了读写),这样避免了不可重复读和脏读,但是有时可能会出现幻读。

4)串行话(读写锁(表))
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上锁。在这个级别,可能导致大量的超时现象和锁竞争;

事务隔离级别脏读不可重复读幻读
读未提交 (read-uncommitted)
读提交(read-committed)
可重复读(repeatable-read)
串行化(serializable)

5 其余常用注解

  1. @Component:将类标记为Spring管理的Bean。@Service、@Repository和@Controller都是特定类型的@Component注解,分别表示服务层、数据访问层和控制层组件。
  2. @Autowired:用于自动装配Bean之间的依赖关系。可以用于构造函数、setter方法或字段上。从Spring 4.3开始,如果只有一个构造函数,可以省略@Autowired。
  3. @Qualifier:当有多个相同类型的Bean时,使用@Qualifier指定特定的Bean进行注入。通常与@Autowired一起使用。
  4. @Value:用于向Bean的属性注入基本类型或String类型的值,支持SpEL表达式。
  5. @Scope:定义Bean的作用域,如singleton(默认)、prototype、request、session和global session。
  6. @PostConstruct:标记一个方法作为初始化方法,该方法会在Bean实例化并设置完所有属性后调用。
  7. @PreDestroy:标记一个方法作为销毁方法,在容器关闭前调用。
  8. @Configuration:将类标记为Spring Java配置类,用于定义和注册Bean。
  9. @Bean:用于@Configuration类中的方法上,声明一个Bean。方法返回的对象将由Spring容器管理。
  10. @ComponentScan:用于Java配置类上,声明启用组件扫描。可以指定扫描的基础包和过滤条件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/347958.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IDEA创建Mybatis项目

IDEA创建Mybatis项目 第一步&#xff1a;创建库表 -- 创建数据库 create database mybatis_db;-- 使用数据库 use mybatis_db;-- 创建user表 CREATE TABLE user (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL,password VARCHAR(50) NOT NULL,email VARC…

Django API开发实战:前后端分离、Restful风格与DRF序列化器详解

系列文章目录 Django入门全攻略&#xff1a;从零搭建你的第一个Web项目Django ORM入门指南&#xff1a;从概念到实践&#xff0c;掌握模型创建、迁移与视图操作Django ORM实战&#xff1a;模型字段与元选项配置&#xff0c;以及链式过滤与QF查询详解Django ORM深度游&#xff…

第十五届蓝桥杯大赛 国赛 pb组F题【括号与字母】(15分) 栈的应用

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 试题F:括号与字母 【问题描述】 给定一个仅包含小写字母和括号的字符串 S …

【CentOS 7】挑战探索:在CentOS 7上实现Python 3.9的完美部署指南

【CentOS 7】挑战探索&#xff1a;在CentOS 7上实现Python 3.9的完美部署指南 大家好 我是寸铁&#x1f44a; 总结了一篇【CentOS 7】挑战探索&#xff1a;在CentOS 7上实现Python 3.9的完美部署指南详细步骤✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 此篇教程只适用于p…

LeetCode 算法: 旋转图像c++

原题链接&#x1f517;&#xff1a; 旋转图像 难度&#xff1a;中等⭐️⭐️ 题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图…

OrangePi AIpro小试牛刀-目标检测(YoloV5s)

非常高兴参加本次香橙派AI Pro&#xff0c;香橙派联合华为昇腾打造的一款AI推理开发板评测活动&#xff0c;以前使用树莓派Raspberry Pi4B 8G版本&#xff0c;这次有幸使用国产嵌入式开发板。 一窥芳容 这款开发板搭载的芯片是和华为昇腾的Atlas 200I DK A2同款的处理器&#…

服务器通的远程桌面连接不上,服务器通的远程桌面连接不上解决方法

当面临服务器远程桌面连接不上的问题时&#xff0c;专业的处理方式需要遵循一系列步骤来确保问题得到准确且高效的解决。以下是一些建议的解决方法&#xff1a; 一、初步排查与诊断 1. 检查网络连接&#xff1a; - 确保本地计算机与服务器之间的网络连接是稳定的。 - 尝…

【万方数据库爬虫简单开发(自用)】

万方数据库爬虫简单开发&#xff08;自用&#xff09;&#xff08;一&#xff09; 使用Python爬虫实现万方数据库论文的搜索并获取信息1.获取url2.输入关键词3.使用BeautifulSoup解析4.获取文章标题信息 使用Python爬虫实现万方数据库论文的搜索并获取信息 后续会逐步探索更新…

【Mac】Downie 4 for Mac(视频download工具)兼容14系统软件介绍及安装教程

前言 Downie 每周都会更新一个版本适配视频网站&#xff0c;如果遇到视频download不了的情况&#xff0c;请搜索最新版本https://mac.shuiche.cc/search/downie。 注意&#xff1a;Downie Mac特别版不能升级&#xff0c;在设置中找到更新一列&#xff0c;把自动更新和自动downl…

【数据结构】二叉树:一场关于节点与遍历的艺术之旅

专栏引入 哈喽大家好&#xff0c;我是野生的编程萌新&#xff0c;首先感谢大家的观看。数据结构的学习者大多有这样的想法&#xff1a;数据结构很重要&#xff0c;一定要学好&#xff0c;但数据结构比较抽象&#xff0c;有些算法理解起来很困难&#xff0c;学的很累。我想让大家…

QT中为程序加入超级管理员权限

QT中为程序加入超级管理员权限 Chapter1 QT中为程序加入超级管理员权限1. mingw编译器2. MSVC编译器3. CMAKE Chapter2 如何给QT程序添加管理员权限(UAC)的几种方法1、Qt Creator中方案一&#xff1a;&#xff08;仅适用于使用msvc编译器&#xff09;方案二&#xff1a;&#x…

uniapp地图自定义文字和图标

这是我的结构&#xff1a; <map classmap id"map" :latitude"latitude" :longitude"longitude" markertap"handleMarkerClick" :show-location"true" :markers"covers" /> 记住别忘了在data中定义变量…

【目标检测】基于深度学习的车牌识别管理系统(含UI界面)【python源码+Pyqt5界面 MX_002期】

系统简介&#xff1a; 车牌识别技术作为经典的机器视觉任务&#xff0c;具有广泛的应用前景。通过图像处理方法&#xff0c;车牌识别技术能够对车牌上的字符进行检测、定位和识别&#xff0c;从而实现计算机对车牌的智能化管理。在现实生活中&#xff0c;车牌识别系统已在小区停…

springboot宠物领养管理系统计算机毕业设计源码46534

摘 要 网络发布信息有其突出的优点&#xff0c;即信息量大&#xff0c;资源丰富&#xff0c;更新速度快等&#xff0c;很符合人们希望以捷、便利的方式获得最多最有效信息的要求。本系统就是一个网上宠物领用的系统&#xff0c;为宠物爱好者提供一个信息发布的平台&#xff0c…

webshell获取总结(cms获取方法、非cms获取方法、中间件拿Webshell方法)

目录 前期准备&#xff1a; 1、cookices靶场网站搭建&#xff1a; 2、dedecms靶场环境搭建&#xff1a; 获取Webshell方法总结&#xff1a; 一、CMS获取Webshell方法 二、非CMS获取Webshell方法 1、数据库备份获取Webshell 例如&#xff1a; 2、抓包上传获取Webshell 3、…

推荐这两款AI工具,真的很好用

巨日禄 巨日禄是一款由杭州巨日禄科技有限公司开发的AI工具&#xff0c;主要功能是将文本内容转换为视频。该工具通过分析大量的剧本数据和影视作品&#xff0c;为用户提供各种类型的故事情节和角色设置&#xff0c;帮助用户快速找到灵感&#xff0c;减少构思剧本的困难和犹豫。…

黑苹果睡眠总是自动唤醒(RTC)

黑苹果睡眠总是自动唤醒【RTC】 1. 问题2. 解决方案2.1. 查看重启日志2.2. 配置Disable RTC wake scheduling补丁 3. 后续4. 参考 1. 问题 黑苹果EFI 更换后&#xff0c;总是在手动 睡眠后&#xff0c;间歇性重启&#xff0c;然后再次睡眠&#xff0c;然后再重启。原因归结为&…

matrix-breakout-2-morpheus vulnhub靶场

端口扫描 80 81 需要用户名密码登录 目录扫描 robots.txt 妹用 找不到利用点&#xff0c;换个扫描器再扫 发现新的文件 graffiti.txt graffiti.php 输入的数据Post后会回显到页面上 抓包看看&#xff0c;居然直接传文件路径 发现我们post的数据被写入了graffiti.…

一种基于单片机的智能饮水机设计

随着人们生活水平的提高&#xff0c;对美好生活质量的追求也越来越高。饮 水机是人们日常生活不可或缺的&#xff0c;实现饮水机的智能化控制不但方便&#xff0c; 而且更加安全。本文提出一种基于单片机的智能饮水控制系统&#xff0c;通过传 感器实现对水温的监测&#xff0c…

最新下载:CorelDraw 2023【软件附加安装教程】

简介&#xff1a; CorelDRAW Graphics Suite 订阅版拥有配备齐全的专业设计工具包&#xff0c;可以通过非常高的效率提供令人惊艳的矢量插图、布局、照片编辑和排版项目。价格实惠的订阅就能获得令人难以置信的持续价值&#xff0c;即时、有保障地获得独家的新功能和内容、一流…