Spring笔记
目录
一、Spring概述
二、Spring IoC — 基于XML
三、Spring IoC — 基于注解
四、代理设计模式
五、Spring AOP
六、Spring AOP 注解配置
七、Spring整合MyBatis
八、基于Spring的单元测试
一、Spring概述
1.1 web项目开发中的耦合度问题
-
在Servlet中需要调用service中的方法,则需要在Servlet类中通过new关键字创建Service的实例
public interface ProductService{public List<Product> listProducts(); }
public class ProductServiceImpl1 implements ProductService{public List<Product> listProducts(){//查询热销商品} }
public class ProductServiceImpl2 implements ProductService{public List<Product> listProducts(){//查询好评商品} }
public class ProductListServlet extends HttpServlet{//在servlet中使用new关键字创建ProductServiceImpl1对象,增加了servlet和service的耦合度private ProductService productService = new ProductServiceImpl1();protected void doGet(HttpServletRequest request,HttpServletResponse response){doPost(request,response);}protected void doPost(HttpServletRequest request,HttpServletResponse response){productService.listProducts();} }
-
在service实现类中需要调用DAO中的方法,也需要在servcie实现类通过new关键字创建DAO实现类对象
-
如果使用new关键字创建对象:
-
失去了面向接口编程的灵活性
-
代码的侵入性增强(增加了耦合度)、降低了代码的灵活性
-
增强项目的扩展性
-
1.2 面向接口编程
面向接口编程 |
---|
解决方案
:在Servlet中定义Service接口的对象变量,不使用new关键字创建实现类对象,在servlet的实例化的时候,通过反射动态的给Service对象变量赋值。
如何实现
:Spring可以做到!!!
1.3 Spring介绍
Spring是一个
轻量级的控制反转和面向切面的容器
框架,用来解决企业项目开发的复杂度问题—解耦
-
轻量级:体积小,对代码没有侵入性
-
控制反转:IoC(Inverse of Control),把创建对象的工作交由Spring完成,Spring在创建对象的时候同时可以完成对象属性赋值(DI)
-
面向切面:AOP(Aspect Oriented Programming)面向切面编程,可以在不改变原有业务逻辑的情况下实现对业务的增强
-
容器:实例的容器,管理创建的对象
1.4 Spring架构
-
官网 Spring | Home
-
Spring架构图
-
1.4.1 Core Container
Spring容器组件,用于完成实例的创建和管理
core
beans 实例管理
context 容器上下文
1.4.2 AOP、Aspects
Spring AOP组件,实现面向切面编程
aop
aspects
1.4.3 web
Spring web组件实际指的是SpringMVC框架,实现web项目的MVC控制
web (Spring对web项目的支持)
webmvc (SpringMVC组件)
1.4.4 Data Access
Spring数据访问组件,也是一个基于JDBC封装的持久层框架(即使没有mybatis,Spring也可以完成持久化操作)
tx
1.4.5 Test
Spring的单元测试组件,提供了Spring环境下的单元测试支持
test
二、Spring IoC — 基于XML
Spring IoC 容器组件,可以完成对象的创建、对象属性赋值、对象管理
2.1 Spring框架部署(IoC)
2.1.1 创建Maven工程
-
Java
-
Web
2.1.2 添加SpringIoC依赖
-
core
-
beans
-
aop
-
expression
-
context
<!--导入contextjar包包含了了其它四个的jar包-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.13.RELEASE</version>
</dependency>
2.1.3 创建Spring配置文件
通过配置文件"告诉"Spring容器创建什么对象,给对象属性赋什么值
-
在resources目录下创建名为
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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 对于一个xml文件如果作为框架的配置文件,需要遵守框架的配置规则 --><!-- 通常一个框架为了让开发者能够正确的配置,都会提供xml的规范文件(dtd\xsd) --></beans>
2.2 SpringIoC使用
使用 SpringIoC组件创建并管理对象
2.2.1 创建一个实体类
public class Student {
private String stuNum;private String stuName;private String stuGender;private int stuAge;private Date enterenceTime; //入学日期
}
2.2.2 在Spring配置文件中配置实体类
<?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将实体类配置给Spring进行管理,id表示实体类的唯一表示--><bean id="stu" class="com.qfedu.ioc.bean.Student"><property name="stuNum" value="10002"/><property name="stuName" value="李斯"/><property name="stuGender" value="女"/><property name="stuAge" value="20"/></bean>
</beans>
2.2.3 初始化Spring对象工厂,获取对象
-
ClassPathXMLApplicationContext
//1.初始化Spring容器,加载Spring配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过Spring容器获取Student对象
Student student2 = (Student) context.getBean("stu");
2.3 IoC和DI
-
IoC (Inverse of Control) 控制反转,通过Spring对象工厂完成对象的创建
-
DI (Dependency Injection)依赖注入,在Spring完成对象创建的同时依赖Spring容器完成对象属性的赋值
-
谈谈对Spring IOC的理解 - 孤傲苍狼 - 博客园
-
2.3.1 IoC
当我们需要通过Spring对象工厂创建某个类的对象时候,需要将这个交给Spring管理——通过bean标签配置
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="com.qfedu.ioc.bean.Student"></bean>
<bean id="book" class="com.qfedu.ioc.bean.Book"></bean>
2.3.2 DI
通过Spring容器给创建的对象属性赋值
<bean id="clazz" class="com.qfedu.ioc.bean.Clazz"></bean>
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="com.qfedu.ioc.bean.Student" autowire="byName"><property name="stuNum" value="10001"/>
</bean>
2.4 DI依赖注入
2.4.1 依赖注入三种方式
Spring容器加载配置文件之后,通过
反射
创建类的对象,并给属性赋值;Spring容器通过反射实现属性注入有三种方式:
set方法注入
构造器注入
接口注入(不常用)
2.4.2 set方法注入
在bean标签中通过配置property标签给属性属性赋值,实
际上就是通过反射调用set方法完成属性的注入
简单类型及字符串
-
直接通过property标签的value属性赋值
<!--通过bean将实体类配置给Spring进行管理,id表示实体类的唯一表示-->
<bean id="stu" class="com.qfedu.ioc.bean.Student" autowire="byName"><!-- 简单类型 --><property name="stuNum" value="10001"/><property name="stuAge" value="12"/><!-- 字符串类型--><property name="weight" value="62.3"/>
</bean>
日期类型
-
方式1:在property标签中通过ref引用Spring容器中的一个对象
<bean id="date" class="java.util.Date"></bean>
<bean id="stu" class="com.qfedu.ioc.bean.Student" ><!-- 日期类型--><property name="enterenceTime" ref="date"/>
</bean>
-
方式2:在property标签中添加子标签bean来指定对象
<bean id="stu" class="com.qfedu.ioc.bean.Student" ><!-- 日期类型--><property name="enterenceTime"><bean class="java.util.Date"/></property>
</bean>
-
方式3
<!--日期格式化--> < bean id = "simpleDateFormat" class = "java.text.SimpleDateFormat" >< constructor-arg value = "yyyy-MM-dd" ></ constructor-arg > </ bean >< bean id = "dateTest" class = "com.yiibai.pojo.DateTest" >< property name = "date" ><!-- 下面这个bean是用来将String对象转换为Date对象的 --><!-- factory-bean表示可以创建Date的工厂类 , factory-method 调用工厂的方法 ->< bean factory-bean = "simpleDateFormat" factory-method = "parse" ><!--向工厂类构造器传的值-->< constructor-arg value = "2017-11-24" ></ constructor-arg ></ bean ></ property > </ bean ><!--或者改成以下,可以使date类型数据赋值的代码复用--> < bean id = "simpleDateFormat" class = "java.text.SimpleDateFormat" >< constructor-arg value = "yyyy-MM-dd" ></ constructor-arg > </ bean > <bean id = "date" factory-bean = "simpleDateFormat" factory-method = "parse" ><!--向工厂类构造器传的值-->< constructor-arg value = "2017-11-24" ></ constructor-arg > </bean > < bean id = "dateTest" class = "com.yiibai.pojo.DateTest" >< property name = "date" ref="date" /> </bean>
<java中的代码实现,可以将任意日期字符串输出> public String toString() {SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd"); return "Student{" +"stuNum='" + stuNum + '\'' +", stuName='" + stuName + '\'' +", stuGender='" + stuGender + '\'' +", stuAge=" + stuAge +", enterenceTime=" + sim.format(enterenceTime) +'}';}
自定义类对象属性
-
方式1:
<bean id="cla" class="com.qfedu.ioc.bean.Clazz"><property name="classId" value="2010"/><property name="className" value="Java2010"/>
</bean>
<bean id="stu" class="com.qfedu.ioc.bean.Student"><!-- 自定义对象类型--><property name="clazz" ref="cla"/>
</bean>
-
方式2
<bean id="stu" class="com.qfedu.ioc.bean.Student"><!-- 自定义对象类型--><property name="clazz"><bean class="com.qfedu.ioc.bean.Clazz"><property name="classId" value="2010"/><property name="className" value="Java2010"/></bean></property>
</bean>
集合类型
-
List
-
List<String> List中的元素是字符串或者简单类型的封装类
-
以下都在<bean id="stu" class="com.qfedu.ioc.bean.Student"></bean>标签中
-
第一种方式
<property name="hobbies" value="旅游,电影"/>
第二种方式
<property name="hobbies" ><list><value>旅游</value><value>电影</value><value>Java</value></list> </property>
-
List<Object> List中的元素是对象类型
<property name="hobbies" ><list><bean class="com.qfedu.ioc.bean.Book"/><bean class="com.qfedu.ioc.bean.Book"/><bean class="com.qfedu.ioc.bean.Book"/><bean class="com.qfedu.ioc.bean.Book"/></list> </property> <!--自己写的案例--><property name="books"><list><bean class="com.xzr.ioc.Book"><property name="bookName" value="西游记"/></bean><bean class="com.xzr.ioc.Book"><property name="bookName" value="红楼梦"/></bean></list> </property>
<property name="hobbies" ><list><!--此方法无法像上面案例一样可以变换bookName值--><ref bean="book"></ref> <!--引用容器中的备案--><ref bean="book"></ref></list> </property>
-
-
Set
<property name="sets"><set><!--和list元素注入方式相同--></set> </property>
-
Map
<property name="maps"><map><entry><key><value>k1</value></key><value>123</value></entry><entry><key><value>k2</value></key><value>456</value></entry></map> </property>
-
Properties
<property name="properties"><props><prop key="k1">aaa</prop><prop key="k2">bbb</prop></props> </property>
2.4.3 构造器注入
简单类型、字符串、对象
public class Student {
private String stuNum;private String stuName;private String stuGender;private int stuAge;private double weight;private Date enterenceTime; //入学日期private Clazz clazz;
public Student(String stuNum, String stuName, String stuGender, int stuAge, double weight, Date enterenceTime, Clazz clazz) {this.stuNum = stuNum;this.stuName = stuName;this.stuGender = stuGender;this.stuAge = stuAge;this.weight = weight;this.enterenceTime = enterenceTime;this.clazz = clazz;}
}
<bean id="date" class="java.util.Date"></bean>
<bean id="stu" class="com.qfedu.ioc.bean.Student"><constructor-arg index="0" value="10001"/> <!--字符串类型--><constructor-arg index="2" value="女"/><constructor-arg index="1" va lue="张三"/><constructor-arg index="3" value="21"/> <!--简单类型--><constructor-arg index="4" value="62.5"/><constructor-arg index="5" ref="date"/> <!--对象类型--><constructor-arg index="6"> <!--对象类型--><bean class="com.qfedu.ioc.bean.Clazz"></bean></constructor-arg>
</bean>
集合类型属性
public class Student{private List<String> hobbies;private Set<String> sets;private Map<String,Object> maps;private Properties properties;
public Student(List<String> hobbies, Set<String> sets, Map<String, Object> maps, Properties properties) {this.hobbies = hobbies;this.sets = sets;this.maps = maps;this.properties = properties;}
}
<bean id="stu1" class="com.qfedu.ioc.bean.Student"><constructor-arg index="0"><list><value>11</value><value>22</value><value>33</value></list></constructor-arg><constructor-arg index="1"><set><value>aa</value><value>bb</value><value>cc</value></set></constructor-arg><constructor-arg index="2"><map><entry><key><value>key1</value></key><value>value1</value></entry><entry><key><value>key2</value></key><value>value2</value></entry></map></constructor-arg><constructor-arg index="3"><props><prop key="k1">v1</prop><prop key="k2">v2</prop></props></constructor-arg>
</bean>
2.5 Bean的作用域
在bean标签可以通过scope属性指定对象的的作用域
scope="singleton" 表示当前bean是单例模式(默认饿汉模式,Spring容器初始化阶段就会完成此对象的创建;当在bean标签中设置 lazy-init="true"变为懒汉模式)
scope="prototype" 表示当前bean为非单例模式,每次通过Spring容器获取此bean的对象时都会创建一个新的对象
-
单例
<bean id="book" class="com.qfedu.ioc.bean.Book" scope="默认值singleton" lazy-init="true"></bean>
-
多例
<bean id="book" class="com.qfedu.ioc.bean.Book" scope="prototype"></bean>
2.6 Bean的声明周期方法
在bean标签中通过init-method属性指定当前bean的初始化方法,初始化方法在构造器执行之后执行,通过destroy-method属性指定当前bean的销毁方法,销毁方法在对象销毁之前执行-->
-
Bean类
public class Book { private int bookId;private String bookName; //初始化方法:在创建当前类对象时调用的方法,进行一些资源准备工作public void init(){System.out.println("-------init");} //销毁方法:在Spring容器销毁对象时调用此方法,进行一些资源回收性的操作public void destory(){System.out.println("-------destory");} }
-
Spring配置文件
<bean id="book" class="com.qfedu.ioc.bean.Book" scope="prototype"init-method="init" destroy-method="destory" ></bean>
2.7 自动装配
自动装配:Spring在实例化当前bean的时候, 从Spring容器中找到匹配的实例, 赋值给当前bean的属性
自动装配策略有两种:
byName 根据当前Bean的属性名在Spring容器中寻找匹配的对象 ,如果根据name找到了bean但是类型不匹配则抛出异常
byName只会自动寻找其他Bean的 id值是否为当前Bean属性所需要赋值的属性名 , 如果当前属性值是clazz , 而Clazz Bean的id值是clazz,则匹配 . 如果是clazz2或者其它值 , 则找不到.
byType 根据当前Bean的属性类型在Spring容器中寻找匹配的对象,如果根据类型找到了多个bean也会抛出异常
-
byName
<bean id="clazz" class="com.qfedu.ioc.bean.Clazz"></bean>
<!-- 只会寻找上面id为calzz的
id值非clazz但是依然是Clazz Bean的标签也不行! 例如:<bean id="clazz2" class="com.qfedu.ioc.bean.Clazz"> -->
<bean id="stu2" class="com.qfedu.ioc.bean.Student" autowire="byName"></bean>
-
byType
<bean id="clazz2" class="com.qfedu.ioc.bean.Clazz"></bean>
<bean id="stu2" class="com.qfedu.ioc.bean.Student" autowire="byType"></bean>
2.7.1 使用案例
public class ShoppingServlet {
private Service service;//凡是依赖注入,都需要给予set方法public void setService(Service service){this.service = service;}
public void doGet(){doPost();}
public void doPost(){service.buy();}
}
public class ServiceImpl implements Service {
public void buy(){System.out.println("您购买了商品");}
}
<!--Servlet使用案例-->
<bean id="service" class="com.xzr.ioc.service.Impl.ServiceImpl"/>
<bean id="shoppingServlet" class="com.xzr.ioc.servlets.ShoppingServlet" autowire="byName"/>
2.8 SpringIoC 工作原理
三、Spring IoC — 基于注解
SpringIoc的使用,需要我们通过XML将类声明给Spring容器进行管理,从而通过Spring工厂完成对象的创建及属性值的注入;
Spring除了提供基于XML的配置方式,同时提供了基于注解的配置:直接在实体类中添加注解声明给Spring容器管理,以简化开发步骤。
3.1 Spring框架部署
3.1.1 创建Maven项目
略
3.2.2 添加SpringIoC依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.13.RELEASE</version>
</dependency>
3.2.3 创建Spring配置文件
-
因为Spring容器初始化时,只会加载applicationContext.xml文件,那么我们在实体类中添加的注解就不会被Spring扫描,所以我们需要
在applicationContext.xml声明Spring的扫描范围
,以达到Spring初始化时扫描带有注解的实体类并完成初始化工作
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
<!-- 声明使用注解配置 --><context:annotation-config/>
<!-- 声明Spring工厂注解的扫描范围 --><context:component-scan base-package="com.qfedu.beans"/>
</beans>
3.2 IoC常用注解
3.2.1 @Component
-
类注解,声明此类被Spring容器进行管理,相当于bean 标签的作用
-
@Component(value="stu")
value属性用于指定当前bean的id,相当于bean标签的id属性;value属性也可以省略,如果省略当前类的id默认为类名首字母改小写 -
除了@Component之外 @Service、@Controller、@Repository这三个注解也可以将类声明给Spring管理,他们主要是语义上的区别
-
@Controller 注解主要声明将控制器类配置给Spring管理,例如Servlet
-
@Service 注解主要声明业务处理类配置Spring管理,Service接口的实现类
-
@Repository 直接主要声明持久化类配置给Spring管理,DAO接口
-
@Component 除了控制器、servcie和DAO之外的类一律使用此注解声明
如何像xml配置那样给属性赋值?
给类设置默认值,就是在类中给属性设置默认值
-
3.2.2 @Scope
-
类注解,用于声明当前类单例模式还是 非单例模式,相当于bean标签的scope属性
-
@Scope("prototype") 表示声明当前类为非单例模式(默认单例模式)
3.2.3 @Lazy
-
类注解,用于声明一个单例模式的Bean是否为懒汉模式
-
@Lazy(true) 表示声明为懒汉模式,默认为饿汉模式
3.2.4 @PostConstruct
在方法前注解
-
方法注解,声明一个方法为当前类的初始化方法(在构造器之后执行),相当于bean标签的init-method属性
3.2.5 @PreDestroy
-
方法注解,声明一个方法为当前类的销毁方法(在对象从容器中释放之前执行),相当于bean标签的destory-method属性
3.2.6 @Autowired
在属性前注解
-
属性注解、方法注解(set方法),声明当前属性自动装配,默认byType 方法注解和属性注解在这里是相同作用
-
@Autowired(required = false) 通过requried属性设置当前自动装配是否为必须,设置false就按属性类型找,找到则返回对象,找不到就是默认值null(默认必须——如果没有找到类型与属性类型匹配的bean则抛出异常)
-
byType
-
ref引用 ( 通过byType找到了多个 , 所以 用@Quelifier("") 指定使用哪一个 )
@Qualifier(" clazz ") 是表明当前匹配多个相同类型对象 , 按照name在这些相同类型对象里找,找到name相同返回对象,如果一个其它类注解为@Component(“ clazz ”),即使找到也会报类型错误
<!--多态的子类也会被byType识别,所以一般用byName -->
@Autowired public void setClazz(@Qualifier("clazz") Clazz clazz) {this.clazz = clazz; }
-
3.2.7 @Resource
-
属性注解,也用于声明属性自动装配
-
默认装配方式为byName,如果根据byName没有找到对应的bean,则继续根据byType寻找对应的bean,根据byType如果依然没有找到Bean或者找到不止一个类型匹配的bean,则抛出异常。
四、代理设计模式
4.1 生活中的代理
代理设计模式的优点:将通用性的工作都交给代理对象完成,被代理对象只需专注自己的核心业务。
4.2 静态代理
静态代理,代理类只能够为特定的类生产代理对象,不能代理任意类
下面不足的地方就是MyStaticProxy类应该实现GenaralDao接口
一个典型的静态代理模式通常有三个角色,这里称之为代理三要素 ,
共同接口
,真实对象
,代理对象
使用代理的好处
1.被代理类中只用关注核心业务的实现,将通用的管理型逻辑(事务管理、日志管理)和业务逻辑分离
2.将通用的代码放在代理类中实现,提供了代码的复用性
3.通过在代理类添加业务逻辑,实现对原有业务逻辑的扩展(增强)
使用代理的缺点
4.3 动态代理
动态代理,几乎可以为所有的类产生代理对象
动态代理的实现方式有2种:
JDK动态代理
CGLib动态代理
4.3.1 JDK动态代理
-
JDK动态代理类实现:
/**** JDK动态代理:是通过被代理对象实现的接口产生其代理对象的* 1.创建一个类,实现InvocationHandler接口,重写invoke方法* 2.在类种定义一个Object类型的变量,并提供这个变量的有参构造器,用于将被代理对象传递进来* 3.定义getProxy方法,用于创建并返回代理对象*/
public class JDKDynamicProxy implements InvocationHandler {//被代理对象private Object obj;public JDKDynamicProxy(Object obj) {this.obj = obj;}//产生代理对象,返回代理对象public Object getProxy(){//1.获取被代理对象的类加载器ClassLoader classLoader = obj.getClass().getClassLoader();//2.获取被代理对象的类实现的接口Class<?>[] interfaces = obj.getClass().getInterfaces();//3.产生代理对象(通过被代理对象的类加载器及实现的接口)//第一个参数:被代理对象的类加载器//第二个参数:被代理对象实现的接口//第三个参数:使用产生代理对象调用方法时,用于拦截方法执行的处理器//第三个参数也可以不用实现接口(不推荐) 直接创建InvocationHandler内部类, 然后传递这个内部类对象名到第三个参数Object proxy = Proxy.newProxyInstance(classLoader, interfaces,this);return proxy;}//调用被代理对象的任何方法,都会被jvm导向这个invoke方法,详情见Nyima动态代理笔记的知乎连接// args是调用方法时传入的该方法需要的参数public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {begin();Object returnValue = method.invoke(obj,args); //执行method方法(insert)commit();return returnValue;}
public void begin(){System.out.println("----------开启事务");}
public void commit(){System.out.println("----------提交事务");}
}
-
测试
//创建被代理对象
BookDAOImpl bookDAO = new BookDAOImpl();
StudentDAOImpl studentDAO = new StudentDAOImpl();
//创建动态代理类对象,并将被代理对象传递到代理类中赋值给obj
JDKDynamicProxy jdkDynamicProxy = new JDKDynamicProxy(studentDAO);
//proxy就是产生的代理对象:产生的代理对象可以强转成被代理对象实现的接口类型 ---------------->重要 底下被强转的是接口不是实现类
GenaralDAO proxy = (GenaralDAO)jdkDynamicProxy.getProxy();
//使用代理对象调用方法,并不会执行调用的方法,而是进入到创建代理对象时指定的InvocationHandler类种的invoke方法
//调用的方法作为一个Method参数,传递给了invoke方法
proxy.insert(student);
4.3.2 CGLib动态代理
由于JDK动态代理是通过被代理类实现的接口来创建代理对象的,因此JDK动态代理只能代理实现了接口的类的对象。如果一个类没有实现任何接口,该如何产生代理对象呢?
CGLib动态代理,是通过
创建
被代理类的子类来创建代理对象的,因此即使没有实现任何接口的类也可以通过CGLib产生代理对象CGLib动态代理不能为final类创建代理对象
-
添加CGLib的依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
-
CGLib动态代理实现:
/*** 1.添加cglib依赖* 2.创建一个类,实现MethodInterceptor接口,同时实现接口中的intercept方法* 3.在类中定义一个Object类型的变量,并提供这个变量的有参构造器,用于传递被代理对象* 4.定义getProxy方法创建并返回代理对象(代理对象是通过创建被代理类的子类来创建的)*/
public class CGLibDynamicProxy implements MethodInterceptor {
private Object obj;public CGLibDynamicProxy(Object obj) {this.obj = obj;}
public Object getProxy(){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(obj.getClass());enhancer.setCallback(this);Object proxy = enhancer.create();return proxy;}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {begin();Object returnValue = method.invoke(obj,objects); //通过反射调用被代理类的方法commit();return returnValue;}
public void begin(){System.out.println("----------开启事务");}
public void commit(){System.out.println("----------提交事务");}
}
-
测试
//创建被代理对象
BookDAOImpl bookDAO = new BookDAOImpl();
StudentDAOImpl studentDAO = new StudentDAOImpl();
//通过cglib动态代理类创建代理对象
CGLibDynamicProxy cgLibDynamicProxy = new CGLibDynamicProxy(bookDAO);
//代理对象实际上是被代理对象子类,因此代理对象可直接强转为被代理类类型
BookDAOImpl proxy = (BookDAOImpl) cgLibDynamicProxy.getProxy();
//使用对象调用方法,实际上并没有执行这个方法,而是执行了代理类中的intercept方法,将当前调用的方法以及方法中的参数传递到intercept方法
proxy.update();
五、Spring AOP
5.1 AOP 概念
Aspect Oriented Programming 面向切面编程,是一种利用“横切”的技术(底层实现就是动态代理),对原有的业务逻辑进行拦截,并且可以在这个拦截的横切面上添加特定的业务逻辑,对原有的业务进行增强。
基于动态代理实现在不改变原有业务的情况下对业务逻辑进行增强
5.2 Spring AOP框架部署
5.2.1 创建Maven项目
5.2.2 添加依赖
-
context
-
aspects
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.13.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.13.RELEASE</version>
</dependency>
5.2.3 创建spring配置文件
-
需要引入aop的命名空间
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
5.3 AOP配置—基于XML
在DAO的方法添加开启事务和提交事务的逻辑
5.3.1 创建一个类,定义要添加的业务逻辑
public class TxManager {
public void begin(){System.out.println("-----------开启事务");}
public void commit(){System.out.println("-----------提交事务");}
}
5.3.2 配置aop
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="bookDAO" class="com.qfedu.dao.BookDAOImpl"></bean><bean id="studentDAO" class="com.qfedu.dao.StudentDAOImpl"></bean>
<!----><bean id="txManager" class="com.qfedu.utils.TxManager"></bean><aop:config><!--声明切入点--><aop:pointcut id="book_all" expression="execution(* com.qfedu.dao.*.*(..))"/>
<!--声明txManager为切面类--><aop:aspect ref="txManager"><!--通知--><aop:before method="begin" pointcut-ref="book_all"/><aop:after method="commit" pointcut-ref="book_all"/></aop:aspect></aop:config>
</beans>
今天在使用spring框架来写一个事务织入的时候出现了如下报错: 注意出现如下两个错误都可能是因为没有正确配置proxy-target-class的值导致的: 错误一:No qualifying bean of type ‘com.pjh.service.Imp.serviceImp’ available 错误二: Exception in thread “main” java.lang.ClassCastException: com.sun.proxy.$Proxy8 cannot be cast to XXX-------动态代理(proxy-target-class属性的意义) 这句话的意思大致为:没有类型为’com.pjh.service.Imp.serviceImp”合格的bean可用 为什么? 查阅资料得:这是由于没有配置proxy-target-class导致的 proxy-target-class有两个值:true/false 决定是基于接口的还是基于类的代理被创建。 如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。 如果proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK 基于接口的代理将起作用。 我使用这段代码来获取: 声明:serviceImp是实现service接口的父类 serviceImp bean1 =(serviceImp) classPathXmlApplicationContext.getBean(serviceImp.class); 而serviceImp是一个类而不是一个接口 而我在进行织入的时候没有配置proxy-target-class属性,默认就为proxy-target-class=false,这是基于接口的代理所以报错了 也就是报错的内容 :没有类型为’com.pjh.service.Imp.serviceImp”合格的bean可用 <aop:config><aop:pointcut id="txPointcut" expression="execution(* com.pjh.service.Imp.serviceImp.*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/></aop:config> 解决方案 解决方法一: 当我将代码的proxy-target-class的值改为true的时候就不会报错了,即改为基于类的代理 <aop:config proxy-target-class="true"><aop:pointcut id="txPointcut" expression="execution(* com.pjh.service.Imp.serviceImp.*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/></aop:config> 解决方法二 将传入的参数改为接口,则无需添加proxy-target-class,因为默认就是false,就是基于接口代理 声明:serivce是serviceImp的父类是一个接口 service bean1 =(service) classPathXmlApplicationContext.getBean(service.class); ------------------------------------------------------------------------------------------------------------理解: Spring-AOP也是使用Spring-ioc获得代理对象的 , 所以在使用context.getBean()时需要指定aop用JDK动态代理还是CGLib动态代理,默认是JDK动态代理,proxy-target-class值为true时是CGLib动态代理.------------------------------------------------------------------------------------------------------------如果在配置文件中不为创建的类创建切面,等一些AOP操作,则该类就是普通创建的但是如果声明了切面且进行了一些AOP通知策略,则该类就会被动态代理总结: 只有对被定义为切入点的类,获取该对象时为代理对象而没有被定义为切入点的类,获取该对象时为真实对象
AOP开发步骤
:
1.创建切面类,在切面类定义切点方法
2.将切面类配置给Spring容器
3.声明切入点
4.配置AOP的通知策略
如果要使用Spring-AOP面向切面编程,调用切入点的对象必须通过使用Spring-ioc获取,而这样的获取方式为调用切入点对象的代理对象,因为这样才能进行拦截处理
<!--使用aop:pointcut标签声明切入点:切入点可以是一个方法-->第一个* 表示有无返回值都可以
<aop:pointcut id="book_insert" expression="execution(* com.qfedu.dao.BookDAOImpl.insert())"/>
<!--BookDAOImpl类中所有无参数无返回值的方法-->第二个*表示这个类中所有方法
<aop:pointcut id="book_pc1" expression="execution(void com.qfedu.dao.BookDAOImpl.*())"/>
<!--BookDAOImpl类中所有无返回值的方法-->..表示有无参数都可以的方法
<aop:pointcut id="book_pc2" expression="execution(void com.qfedu.dao.BookDAOImpl.*(..))"/>
<!--BookDAOImpl类中所有无参数的方法-->
<aop:pointcut id="book_pc3" expression="execution(* com.qfedu.dao.BookDAOImpl.*())"/>
<!--BookDAOImpl类中所有方法-->
<aop:pointcut id="book_pc4" expression="execution(* com.qfedu.dao.BookDAOImpl.*(..))"/>
<!--dao包中所有类中的所有方法-->
<aop:pointcut id="pc5" expression="execution(* com.qfedu.dao.*.*(..))"/>
<!--dao包中所有类中的insert方法-->
<aop:pointcut id="pc6" expression="execution(* com.qfedu.dao.*.insert(..))"/>
<!--所有被AOP增强的类中的所有方法-->
<aop:pointcut id="pc7" expression="execution(* *(..))"/>
5.4.2 AOP使用注意事项
//如果要使用Spring aop面向切面编程,调用切入点方法的对象必须通过Spring容器获取
//如果一个类中的方法被声明为切入点并且织入了切点之后,通过Spring容器获取该类对象,实则获取到的是一个代理对象
//如果一个类中的方法没有被声明为切入点,通过Spring容器获取的就是这个类真实创建的对象
//BookServiceImpl bookService = new BookServiceImpl();
BookServiceImpl bookService = (BookServiceImpl) context.getBean("bookServiceImpl");
bookService.addBook();
5.5 AOP通知策略
AOP通知策略:就是声明将切面类中的切点方法如何织入到切入点
before
after
after-throwing
after-returning
around
5.5.1 定义切面类
public class MyAspect {
public void method1(){System.out.println("~~~~~~~method1");}public void method2(){System.out.println("~~~~~~~method2");}public void method3(){System.out.println("~~~~~~~method3");}public void method4(){System.out.println("~~~~~~~method4");}
//环绕通知的切点方法,必须准守如下的定义规则://1.必须带有一个ProceedingJoinPoint类型的参数//2.必须有Object类型的返回值//3.在前后增强的业务逻辑之间执行Object v = point.proceed();//4.方法最后返回vpublic Object method5(ProceedingJoinPoint point) throws Throwable {System.out.println("~~~~~~~method5---before");//此代码的执行,就表示切入点方法的执行Object v = point.proceed();System.out.println("~~~~~~~method5---after");return v;}
}
5.5.2 配置切面类
<bean id="myAspect" class="com.qfedu.utils.MyAspect"></bean>
<aop:config><!--使用aop:pointcut标签声明切入点:切入点可以是一个方法--><aop:pointcut id="book_insert" expression="execution(* com.qfedu.dao.BookDAOImpl.insert())"/>
<aop:aspect ref="myAspect"><!--aop:before 前置通知,切入到指定切入点之前--><aop:before method="method1" pointcut-ref="book_insert"/><!--aop:after 后置通知,切入到指定切入点之后--><aop:after method="method2" pointcut-ref="book_insert"/><!--aop:after-throwing 异常通知,切入点抛出异常之后,可用于事务的回滚--><aop:after-throwing method="method3" pointcut-ref="book_insert"/><!--aop:after-returning 方法返回值返回之后,对于一个Java方法而言return返回值也是方法的一部分因此“方法返回值返回之后”和“方法执行结束”是同一个时间点,随意after 和 after-returning根据配置的顺序决定执行顺序--><aop:after-returning method="method4" pointcut-ref="book_insert"/><!--环绕通知--><aop:around method="method5" pointcut-ref="book_insert"/></aop:aspect>
</aop:config>
六、Spring AOP 注解配置
6.1 Spring AOP 注解配置框架部署
6.1.1 创建Maven工程
6.1.2 添加Spring依赖
-
context
-
aspects
6.1.3 Spring配置文件
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config></context:annotation-config><context:component-scan base-package="com.qfedu"></context:component-scan>
<!-- 基于注解配置的aop代理 -->
<!-- 通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ的bean创建代理,织入切面。当然, spring在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj- autoproxy />隐藏起来了<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为 <aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target- class 设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
6.2 AOP注解配置案例
@Component
@Aspect
public class TransactionManager {
@Pointcut("execution(* com.qfedu.dao.*.*(..))")public void pc1(){}
@Before("pc1()") 不注明上面的切入点,则在这里就写成 @Before("execution(* com.qfedu.dao.*.*(..))"),后面配置一样写成这样public void begin(){System.out.println("~~~~开启事务");}
@After("pc1()")public void commit(){System.out.println("~~~~提交事务");}
@Around("pc1()")public Object printExecuteTime(ProceedingJoinPoint point) throws Throwable {long time1 = System.currentTimeMillis();Object v = point.proceed(); //代表切入点方法执行 , 此句话以上相当于before , 以下相当于afterlong time2 = System.currentTimeMillis();System.out.println("----time:"+(time2-time1));return v;}
}
注意
:注解使用虽然方便,但是只能在源码上添加注解,因此我们的自定义类提倡使用注解配置;但如果如果使用到第三方提供的类则需要通过xml配置形式完成配置。
七、Spring整合MyBatis
Spring两大核心思想:IoC 和 AOP
IoC : 控制反转,Spring容器可以完成对象的创建、属性注入、对象管理等工作
AOP : 面向切面,在不修改原有业务逻辑的情况下,实现原有业务的增强
7.1 Spring可以对MyBatis提供哪些支持?
-
IoC支持 SpringIoC 可以为MyBatis完成DataSource、SqlSessionFactory、SqlSession以及DAO对象的创建
-
AOP支持使用Spring提供的事务管理切面类完成对MyBatis数据库操作中的事务管理
7.2 Spring整合MyBatis准备工作
7.2.1 创建Maven工程
7.2.2 部署MyBatis框架
-
添加依赖
-
Mysql驱动
-
mybatis
-
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version>
</dependency>
-
创建MyBatis配置文件(创建配置文件之后无需进行任何配置)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
</configuration>
7.2.3 部署Spring框架
-
添加依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.13.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.13.RELEASE</version>
</dependency>
<!-- 这个依赖是Spring对持久层的支持 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.13.RELEASE</version>
</dependency>
-
创建Spring配置文件: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"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
7.2.4 添加Spring整合MyBatis的依赖
-
mybatis-spring 就是mybatis提供的兼容Spring的补丁
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.2</version>
</dependency>
7.2.5 spring中的classpath代表哪个目录?
在spring项目的XML中加载db.properties文件配置如下:
<!-- 加载配置文件 --> <context:property-placeholder location="classpath:db.properties"/>
开始不知道classpath是哪个路径,后来发现整个项目运行的时候,不仅仅是java类会被编译成class存放在classes目录下,而且properties文件、xml文件也会放到这个目录下:
所以<param-value>classpath:spring/springmvc.xml</param-value>是指spring目录里面的springmvc.xml文件
故可以把classpath理解成classes目录。
7.3 Spring整合MyBatis整合IoC配置
7.3.1 整合Druid连接池
-
添加druid的依赖
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version>
</dependency>
-
创建druid.properties属性文件
druid.driver=com.mysql.jdbc.Driver
druid.url=jdbc:mysql://localhost:3306/db_2010_mybatis?characterEncoding=utf-8
druid.username=root
druid.password=admin123
## 连接池参数
druid.pool.init=1
druid.pool.minIdle=3
druid.pool.maxActive=20
druid.pool.timeout=30000
-
在applicationContext.xml中配置DruidDataSource
<!--加载druid.properties属性文件-->
<context:property-placeholder location="classpath:druid.properties"/>
<!--依赖Spring容器完成数据源DataSource的创建-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${druid.driver}"/><property name="url" value="${druid.url}"/><property name="username" value="${druid.username}"/><property name="password" value="${druid.password}"/>
<property name="initialSize" value="${druid.pool.init}"/><property name="minIdle" value="${druid.pool.minIdle}"/><property name="maxActive" value="${druid.pool.maxActive}"/><property name="maxWait" value="${druid.pool.timeout}"/>
</bean>
7.3.2 整合MyBatis—创建SqlSessionFactory
依赖Spring容器创建MyBatis的SqlSessionFactory对象
<!--依赖Spring容器完成MyBatis的SqlSessionFactory对象的创建-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" ><!--配置数据源--><property name="dataSource" ref="druidDataSource"/><!--配置mapper文件的路径--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--配置需要定义别名的实体类的包-->设置这个 那么在Mapper文件里面就可以直接写对应的类名首字母小写 而不用写全路径名了<property name="typeAliasesPackage" value="com.qfedu.pojo"/><!--可选:配置MyBatis的主配置文件 例如二级缓存和一些插件--><property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
7.3.3 整合MyBatis-创建Mapper
<!--加载dao包中的所有DAO接口,通过sqlSessionFactory获取SqlSession,然后创建所有的DAO接口对象,存储在Spring容器-->
<!--Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/><property name="basePackage" value="com.qfedu.dao"/>
</bean>
// 测试
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");SqlSessionFactory factory = (SqlSessionFactory) context.getBean("sqlSessionFactory");SqlSession sqlSession = factory.openSession();System.out.println(sqlSession);UserDao userDao = (UserDao)context.getBean("userDao");List<User> list = userDao.selectAll();System.out.println(list);}
7.4 Spring整合MyBatis整合AOP配置
使用Spring提供的事务管理切面类 完成DAO中增删改操作的事务管理
7.4.1 事务的隔离级别
isolation 设置事务隔离级别:READ_UNCOMMITTED ,READ_COMMITTED , REPEATABLE_READ , SERIALIZABLE
7.4.2 事务的传播机制
propagation 设置事务的传播机制
-
REQUIRED 如果上层方法没有事务,则创建一个新的事务;如果已经存在事务,则加入到事务中。
-
SUPPORTS 如果上层方法没有事务,则以非事务方式执行;如果已经存在事务,则加入到事务中。
-
REQUIRES_NEW 如果上层方法没有事务,则创建一个新的事务;如果已经存在事务,则将当前事务挂起
(表明把上层事务挂起,自己创建新事务)
。 -
NOT_SUPPORTED 如果上层方法没有事务,则以非事务方式执行;如果已经存在事务,则将当前事务挂起。
表明把上层事务挂起,自己不支持事务,不要把自己放在事务当中
-
NEVER 如果上层方法没有事务,则以非事务方式执行;如果已经存在事务,则抛出异常。
-
MANDATORY 如果上层方法已经存在事务,则加入到事务中执行;如果不存在事务则抛出异常。
-
NESTED 如果上层方法没有事务,则创建一个新的事务;如果已经存在事务,则嵌套到当前事务中。
(表明自己要有事务,如果上层有事务,则自己的事务执行完之后再执行上层事务,这是嵌套)
7.4.3 Spring AOP事务管理配置—XML配置
事务配置通常配置到service包下的类,不应该配置到dao包下
<!--1.将Spring提供的事务管理配置配置给Spring容器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="druidDataSource"/>
</bean>
<!--2.通过Spring jdbc提供的 tx标签,声明事务管理策略-->
<tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes>//事务传播机制<tx:method name="insert*" isolation="REPEATABLE_READ" propagation="REQUIRED"/><tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED"/><tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED"/><tx:method name="query*" isolation="REPEATABLE_READ" propagation="SUPPORTS"/></tx:attributes>
</tx:advice>
<!--3.将事务管理策略以AOP配置 应用于DAO操作方法-->
<!--事务配置应该配置到Service方法上,不应该配置到dao层上,Service上包含了多个dao方法,所有的dao方法都要配置事务吗?这行不通,所以应该在service方法层加事务,管理service方法层内的全部dao方法-->
<原则上也是在service层下配置事务>
<aop:config><aop:pointcut id="crud" expression="execution(* com.qfedu.service.*.*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="crud"/>
</aop:config>
<疑问?:事务传播机制触发之后,当前事务和上层事务隔离级别怎么区分,如果上层事务的隔离级别小于当前事务隔离级别应该怎么办?
//想法!:上层事务一定考虑和知道内部操作数据库的方法,他的隔离级别一定满足内部的dao操作隔离级别的最大范围,所以这个想法有点多余~~~
>
<疑问?:那么为什么这dao方法还需要指定事务传播机制,上层就考虑到了内部dao操作,所以调用dao操作一定是在事务里边啊!
//想法!:因为你有时候直接调用dao操作,而这些dao操作没有上层事务的保护,所以要默认一个事务传播机制,所以事务传播机制主要是为了保护你单独调用他们而没有事务保护点的行为~~~><!--建议:比较难得问题不要空想,有些问题也不需要钻研明白,你只需要知道它的规则,切记不要空想大多数没有接触过的问题-->
7.4.4 Spring AOP事务管理配置—注解配置
-
在applicationContext.xml中配置事务管理,声明使用注解方式进行事务配置
<!--使用注解进行事务管理前提是 IoC需要进行注解配置-->
<context:annotation-config/>
<context:component-scan base-package="com.qfedu"/>
<!--1.将Spring提供的事务管理配置配置给Spring容器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="druidDataSource"/>
</bean>
<!--2.声明使用注解完成事务配置-->
<tx:annotation-driven transaction-manager="transactionManager"/>
-
在需要Spring进行事务管理的方法上添加
@Transactional
注解
@Transactional(isolation = Isolation.REPEATABLE_READ ,propagation = Propagation.SUPPORTS )
public List<User> listUsers() {return userDAO.queryUsers();
}
八、基于Spring的单元测试
如果想要使用Spring容器实现属性注入、实现AOP面向切面编程,对象必须通过Spring容器获取;为了便于Spring环境下的测试,Spring提供了test组件,专门针对Spring环境进行单元测试。
8.1 添加依赖
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.13.RELEASE</version>
</dependency>
8.2 编写单元测试类
8.2.1 创建一个单元测试类
略
8.2.2 添加注解
//1.通过@RunWith 声明当前测试类位于Spring容器环境(被Spring容器管理)
@RunWith(SpringJUnit4ClassRunner.class)
//2.通过@ContextConfiguration 声明当前测试环境的Spring容器运行时加载的配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class UserServiceImplTest {
//因为当前测试类是基于Spring容器运行的,当前测试类的对象是通过Spring容器创建的//因此可以通过Spring容器实现属性的注入@Resourceprivate UserService userServiceImpl2;@Resourceprivate UserService userServiceImpl;
@Testpublic void test(){List<User> users = userServiceImpl.listUsers();System.out.println(users);}
}
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 今天面了个腾讯程序员,基础扎实,当场给30K的offer
公司最近在招人,下午来了个面试者,老大没时间就临时让我去面试了一下。 了解到他是在职的,出来看看有没有好机会,然后我问了些分布式、微服务、性能调优等方面的面试题,不愧是腾讯出来的,整体回答都还算不…...
2024/4/18 5:56:06 - 第三章:顺序结构程序设计
一、华氏温度转换为摄氏温度(代码,注释理解和执行结果) 二、小写字母转换为大写字母(代码,注释理解和执行结果) 三、用循环语句计算100以内偶数之和(代码,注释理解和执行结果&#x…...
2024/4/15 0:56:05 - HTML5期末大作业:动漫网站设计——动漫樱桃小丸子(6页) HTML+CSS+JavaScript 学生DW网页设计作业成品 关于动漫的HTML网页设计
HTML5期末大作业:动漫网站设计——动漫樱桃小丸子(6页) HTMLCSSJavaScript 学生DW网页设计作业成品 关于动漫的HTML网页设计 常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体…...
2024/4/20 8:27:37 - 【量化金融】利用DCF估值模型实现股票价值检测
一、前言 在对一家上市公司开展基本面分析时,通常可以通过其财务数据进行剖析解读,利用上市公司调研等各种渠道实现进行其内在价值的评价。日常中我们常用的财务评价指标可能包括: 1)市盈率(PE)&am…...
2024/4/5 6:00:10 - 遗传算法——01背包问题中的应用 C++
对于01背包问题,本身就附带有一定能出最优解的动态规划算法。但是动态规划算法在大数据集下(30个包以上)可能要花费大量的时间。如果在工业生产中需要快速得出相关问题的结果,那么动态规划等全遍历算法就不是最优方法。这时我们引…...
2024/4/15 0:56:30 - Leetcode 42 接雨水
题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 解题思路 首先得知道,接水的地方是两边高中间低的地方,这里设两边的柱子为 left 和 right,中间的柱子ÿ…...
2024/4/17 23:37:46 - Python正则表达式从零基础到入门
文章目录正则表达式一、初识正则表达式1.1 是什么?1.2 用来干什么?1.3 具体应用1.4 基本组成元素二、正则表达式的匹配规则2.1 匹配字符2.1.1 单个字符2.1.2 多个字符2.1.3 常用的特殊表达式2.2 匹配循环和重复2.2.1 常用的特殊表达式2.3 位置和边界2.3.…...
2024/4/15 0:56:05 - Log4j的日志打印级别理解
之前对log4j日志打印一直没有在意过,等在自己要用的时候却又似懂非懂的样子,今天特意记录一下; 常用的5种日志级别 按照优先级从高到低排序:FATAL, ERROR、WARN、INFO、DEBUG; 通过在配置文件中定义的级别࿰…...
2024/4/7 1:59:00 - 蓝牙定位技术在学校定位中的应用案例浅析
摘要:蓝牙定位技术正在引领工业信息的交融,为工业物联网革新打下基础,帮助提升制造商的功率、产能及安全至更高等级。制造商和经销商通过财物盯梢和办理解决方案优化库存办理并进步运营功率,蓝牙定位技术将成为智能楼宇商场最主要的运用解决方案。 一…...
2024/4/20 10:41:09 - 全方位解读 Java 面试:阿里p8手码 10w 字面试速成手册,我粉了
Java 面试 大家想必也知道现在面试就是看项目经验基本技术个人潜力(也就是值不值得培养)。总之就是每一次面试都是对我们能力的检验(无论是软实力还是硬实力)。软实力其实就是简历包装,自我介绍,与面试官交谈技巧等等;…...
2024/4/15 0:56:15 - c语言递归函数
#include <stdio.h> int main(){int age(int n);printf("No5 age is:%d\n",age(5));return 0; } int age(int n){int c;if(n1)c10;elsecage(n-1)2;return c; }首先执行main函数里面的age(5),通过5这个实参传递到age函数int age(int n)中的形参去,ag…...
2024/4/16 23:35:38 - 排序之选择排序
选择排序 代码 void selSort(int R[], int n) {for(int i0; i<n; i){int temp i;int j;for (ji1; j<n; j){if (R[j]<R[temp])tempj;}if ( temp!i )R[j] ^ R[temp] ^R[j] ^ R[temp];} }原理 先从N个数中找出最小的数,把它与第一个位置的数交换再从N-1个数中找出最小…...
2024/4/7 1:58:57 - Python心得
1.loc函数和iloc函数 loc[n, :] #n行的所有数据 , n代表行数 例如: loc[0, :] #第0行的所有数据 loc[:, days] #days列的所有数据 loc[:, type] #type列的所有数据 2.data_Pivot函数 属于Pandas data_Pivot[(data_Pivot.days…...
2024/4/7 1:58:55 - Android知识路线
帧动画...
2024/4/7 1:58:54 - vue 3.0 form 规则校验-----懂的都懂
查询 setup() { const router useRouter(); const Form ref(null); const state reactive({ form: { industryName: “”, industryDesc: “”, }, dialogVisible: false, loading: false, diaTitle: “新增行业”, tableData: [ { date: “2016-05-04”, name: “Tom”, ad…...
2024/4/19 22:01:15 - EWMA控制图的设计理论与方法
一、EWMA控制图的定义及设计 假设一列Xi,i1,2,⋯X_i,i1,2,\cdotsXi,i1,2,⋯来自一生产过程。为监控此生产过程是否受控,要做如下的假设检验: H0:Xi∼N(μ0,σ02),i≥1⟷H1:Xi∼{N(μ0,σ02),1≤i≤τ,N(μ1,σ12),i>τ,H_0:X_i\sim N(\mu_0,\sigma…...
2024/4/15 0:57:16 - 21电赛02 stm32串口发送接收
stm32串口接收 具体协议看之前的01 //头文件部分 typedef struct {long int x_cm;long int y_cm;int openmv; }OPMV_info; //定义了接收数据用的结构体 extern OPMV_info User_openmv1; extern OPMV_info User_openmv2;void Openmv1_GetOneByte(uint8_t data); void Openmv…...
2024/4/16 6:16:05 - Pycharm简单的爬虫实现——打开网页
用python打开网页: import webbrowser webbrowser.open(http://hongloumeng.5000yan.com/hlm1127.html) 链接可以换成自己喜欢的。如果提示no module就用pip安装。 也可以先将喜欢的网址复制到剪切板中,在这里可以先复制下面代码# 后面的网址到剪切板中&…...
2024/4/15 0:56:56 - 全球及中国多晶硅产业竞争态势及发展前景研究报告2021-2027年
全球及中国多晶硅产业竞争态势及发展前景研究报告2021-2027年 HS--HS--HS--HS--HS--HS--HS--HS--HS--HS--HS--HS-- 【修订日期】:2021年10月 【搜索鸿晟信合研究院查看官网更多内容!】 第一章 多晶硅概述 1.1 多晶硅的定义及相关特性 1.1.1 多晶硅…...
2024/4/15 0:57:01 - lombok 基础注解之 @val
最全的 lombok 注解详情(随着版本不定时更新) 一、注解介绍 作用于类、变量,主要用于声明变量的类型,注解将从初始化程序表达式中推断类型,生成的变量是 final 不可以变 二、实战演练 val public class 杨幂 {publ…...
2024/4/15 0:57:16
最新文章
- PostgreSQL的学习心得和知识总结(一百三十九)|深入理解PostgreSQL数据库GUC参数 allow_alter_system 的使用和原理
目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《PostgreSQL数据库内核分析》 2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》 3、PostgreSQL数据库仓库…...
2024/4/26 0:17:45 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 同一个pdf在windows和linux中的页数不一样
之前认为PDF的格式,至少页数是不会变化的,结果最近发现一个文档在windows和linux中的页数不一样,linux中的pdf进入像word一样排版变得紧凑了,原本在下一页的几行进入了上一页的末尾。问了gpt后得到这样的回答: PDF文档…...
2024/4/21 6:41:42 - Linux mount用法
在Linux系统中,系统自动挂载了以下挂载点: /: xfs文件系统,根文件系统, 所有其他文件系统的挂载点。 /sys: sysfs文件系统,提供内核对象的信息和接口。 /proc: proc文件系统,提供进程和系统信息。 /dev: devtmpfs文件系…...
2024/4/24 0:39:01 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/4/25 11:51:20 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/4/25 18:39:24 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/25 18:38:39 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/4/25 18:39:23 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/25 18:39:22 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/25 18:39:22 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/25 18:39:20 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/25 16:48:44 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/25 13:39:44 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/4/25 18:39:16 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/25 18:39:16 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/25 0:00:17 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/25 4:19:21 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/25 18:39:14 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/4/25 18:39:12 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/25 2:10:52 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/25 18:39:00 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/25 13:19:01 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/4/25 18:38:58 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/25 18:38:57 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57