Spring

1、简介

1.1 简介

Spring : 春天 ————给软件行业带来了春天
2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术

Spring是一个轻量级的Java 开发框架,最根本的使命就是:解决企业级应用开发的复杂性,即简化Java开发。

两个核心特性:依赖注入(DI)和面向切面编程(AOP)。

核心:IoC容器和AOP模块。通过IoC容器管理 POJO对象以及它们之间的耦合关系,通过AOP以动态非侵入的方式增强服务。

1.2 组成

在这里插入图片描述

Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 。

在这里插入图片描述
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

  • 核心容器: 核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring 上下文: Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP: 通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO: JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM: Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块: Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架: MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

1.3 扩展

Spring Boot与Spring Cloud

  • Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;
  • Spring Cloud是基于Spring Boot实现的;
  • Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
  • Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
  • SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。

2、Spring IoC

2.1 Spring IoC阐述

控制反转是一个比较抽象的概念,我们可以举个例子来说明:在实际生活中,人们要用到一样东西时,人们的基本想法就是找到东西,比如想喝橙汁,在没有饮品店的日子里,最直观的想法就是买果汁机、橙子,准备水。这里就像是自己“主动”创造的过程;然而到了现在,想喝橙汁的想法一出现,第一个想法就是找到饮品店的联系方式,通过电话等渠道描述你的需要,然会过一会就会有人送上橙汁。这里橙汁是由饮品店创造的。
有了上面的例子,我们就可以明白 控制反转的概念:控制反转是一种通过描述(在Java中可以是XML或者注释)并通过第三方去产生或获取特定对象的方式。
在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入。Spring会提供IoC容器来管理对应的资源。

2.2 Spring IoC容器的设计和初始化浅谈

Spring IoC容器可以容纳我们所开发的各种Bean,并且可以从中获取各种发布在Spring IoC容器里的Bean,并且通过描述可以得到它。

Spring IoC容器的设计
Spring IoC容器的设计主要是基于BeanFactory和ApplicationContext两个接口,其中ApplicationContext是BeanFactory的子接口之一,换句话说BeanFactory是Spring IoC容器所定义的最底层接口。而ApplicationContext是其高级接口之一,并且对BeanFactory功能做了许多有用的扩展,所以在绝大部分的工作场景下,都会使用ApplicationContext作为Spring IoC容器。

Spring IoC容器的初始化和依赖注入
Bean的定义和初始化在Spring IoC容器中是两大步骤,它是先定义,然后初始化和依赖注入的。
Bean的定义分为三步:

  1. Resource定位,这步是Spring IoC容器根据开发者的配置,进行资源定位,在Spring的开发中,通过XML或者注解是十分常见的方式,定位的内容由开发者所提供。
  2. BeanDefinition的载入,这个时候只是将Resource定位到的信息,保存到Bean定义(BeanDefinition)中,此时并不会创建Bean的实例。
  3. BeanDefinition的注册,这个过程就是将BeanDefinition的信息发布到Spring IoC容器中,注意,此时仍旧没有对应的Bean实例的创建。

做完这三步,Bean就在Spring IoC容器被定义了,而没有被初始化,更没有完成依赖注入,也就是没有注入其配置的资源给Bean,那么他还不能完全使用。对于初始化和依赖注入,Spring Bean还有一个配置选项——lazy-init,其含义就是是否初始化Spring Bean,在没有任何配置的情况下,它的默认值为default,实际值就是false,也就是Spring IoC容器默认会自动初始化Bean。如果将其设置为true,那么只有当我们使用Spring IoC容器的getBean方法获取它时,它才会进行Bean的初始化,完成依赖注入。

2.3 IoC创建对象方式

2.3.1 通过无参构造方法来创建

话不多说,用代码来说明

1、User.java

public class User {private String name;public User() {System.out.println("user无参构造方法");}public void setName(String name) {this.name = name;}public void show(){System.out.println("name="+ name );}}

2、beans.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"><bean id="user" class="com.learn.spring.pojo.User"><property name="name" value="hjw"/></bean></beans>

3、测试类

@Test
public void test(){ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//在执行getBean的时候, user已经创建好了 , 通过无参构造User user = (User) context.getBean("user");//调用对象的方法 .user.show();
}

结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!

2.3.2 通过有参构造方法来创建

1、User.java

public class UserT {private String name;public UserT(String name) {this.name = name;}public void setName(String name) {this.name = name;}public void show(){System.out.println("name="+ name );}}

2、beans.xml 有三种方式编写

<!-- 第一种根据index参数下标设置 -->
<bean id="user" class="com.learn.spring.pojo.User"><!-- index指构造方法 , 下标从0开始 --><constructor-arg index="0" value="hjw"/>
</bean>
<!-- 第二种根据参数名字设置 -->
<bean id="user" class="com.learn.spring.pojo.User"><!-- name指参数名 --><constructor-arg name="name" value="hjw"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="user" class="com.learn.spring.pojo.User"><constructor-arg type="java.lang.String" value="hjw"/>
</bean>

3、测试类

@Test
public void testT(){ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");User user = (User) context.getBean("user");user.show();
}

结论:在配置文件加载的时候。其中管理的对象都已经初始化了!

2.4 Bean

2.4.1 Bean的生命周期

Spring IoC容器的本质目的就是为了管理Bean,对于Bean而言,我们就要了解它的生命周期。
在这里插入图片描述
从上图可以看到,Spring IoC容器对Bean的管理还是比较复杂的,Spring IoC容器在执行了初始化和依赖注入后,会执行一定的步骤来完成初始化,通过这些步骤我们就可以自定义初始化,而在Spring IoC容器正常关闭的时候,他也会执行一定的步骤来关闭容器,释放资源。

下面我用一个实现类来测试一下他的生命周期。

测试文件框架
在这里插入图片描述
BeanPostProcessorImpl.java

package Juice.main.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class BeanPostProcessorImpl implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException{System.out.println("【"+bean.getClass().getSimpleName()+"】对象"+beanName+"开始实例化");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException{System.out.println("【"+bean.getClass().getSimpleName()+"】对象"+beanName+"实例化完成");return bean;}}

JuiceMaker.java

package Juice.main.pojo;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;public class JuiceMakerimplements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {private String beverageShop = null;private Source source = null;public String getBeverageShop() {return beverageShop;}public void setBeverageShop(String beverageShop) {this.beverageShop = beverageShop;}public Source getSource() {return source;}public void setSource(Source source) {this.source = source;}public void init(){System.out.println("【"+this.getClass().getSimpleName()+"】执行自定义初始化方法");}public void myDestory(){System.out.println("【"+this.getClass().getSimpleName()+"】执行自定义销毁方法");}public String makeJuice(){String Juice="这是一杯由"+beverageShop+"饮品店,提供的"+source.getSize()+source.getSugar()+source.getFruit();return Juice;}@Overridepublic void setBeanName(String arg0){System.out.println("【"+this.getClass().getSimpleName()+"】调用BeanNameAware接口的setBeanName方法");}@Overridepublic void setBeanFactory(BeanFactory arg0) throws BeansException{System.out.println("【"+this.getClass().getSimpleName()+"】调用BeanFactoryAware接口的setBeanFactory方法");}@Overridepublic void setApplicationContext(ApplicationContext arg0) throws BeansException{System.out.println("【"+this.getClass().getSimpleName()+"】调用ApplicationContextAware接口的setApplicationContext方法");}@Overridepublic void afterPropertiesSet() throws Exception{System.out.println("【"+this.getClass().getSimpleName()+"】调用InitializingBean接口的afterPropertiesSet方法");}@Overridepublic void destroy() throws Exception{System.out.println("调用接口DisposableBean的destory方法");}
}

Source.java

package Juice.main.pojo;public class Source {private String fruit;   //类型private String sugar;   //糖分描述private Integer size;   //大小杯public String getFruit() {return fruit;}public void setFruit(String fruit) {this.fruit = fruit;}public String getSugar() {return sugar;}public void setSugar(String sugar) {this.sugar = sugar;}public Integer getSize() {return size;}public void setSize(Integer size) {this.size = size;}
}

spring-cfg.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 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"><bean id="beanPostProcessor"class="Juice.main.bean.BeanPostProcessorImpl"></bean><bean id="source" class="Juice.main.pojo.Source"><property name="fruit" value="橙汁"></property><property name="size" value="2"></property><property name="sugar" value="少糖"></property></bean><bean id="juiceMaker" class="Juice.main.pojo.JuiceMaker"init-method="init" destroy-method="myDestory"><property name="beverageShop" value="贡茶"></property><property name="source" ref="source"></property></bean></beans>

test.java

package Juice.test;import Juice.main.pojo.JuiceMaker;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class test {public static void main(String[] args){ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("spring-cfg.xml");JuiceMaker juiceMaker=(JuiceMaker)ctx.getBean("juiceMaker");System.out.println(juiceMaker.makeJuice());ctx.close();}
}

运行结果:
在这里插入图片描述

2.4.2 Bean的装配方式

一般说来,Spring装配Bean有两种方式:

  • 通过XML配置装配Bean
  • 通过注解配置装配Bean

通过XML配置装配Bean

使用XML装配Bean需要定义对应的XML,这里需要引入对应的XML模式(XSD)文件,这些文件会定义配置Spring Bean的一些元素,一个简单的模板如下:

<?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"><!-- 配置代码  -->
</beans>

装配简单值

先来一个最简单的装配,XML代码如下:

    <bean id="source" class="Juice.main.pojo.Source"><property name="fruit" value="橙汁"></property><property name="size" value="2"></property><property name="sugar" value="少糖"></property></bean>

简单的解释一下:

  • id属性是Spring找到的这个Bean的编号,不过id不是一个必需的属性,如果没有声明它,那么Spring将会采用 “全限定名#{number}” 的格式生产编号。如果只声明了这样的类,而没有声明id,那么SPring为其生产的编号就是“com.ssm.learn.pojo.Role#0”。
  • class显然就是一个类的全限定名。
  • property元素是定义类的属性,其中name属性定义的是属性名称,而value是其值。

装配集合

有时候要做一些复制的装配工作,比如Set、Map、Array和Properties等。为了很好的介绍,我们举一个例子来说明一下。首先我们新建一个Bean,代码如下:

package Juice.main.pojo;import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;public class complex {private Long id;private List<String> list;private Map<String,String> map;private Properties props;private Set<String> set;private String[] array;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public List<String> getList() {return list;}public void setList(List<String> list) {this.list = list;}public Map<String, String> getMap() {return map;}public void setMap(Map<String, String> map) {this.map = map;}public Properties getProps() {return props;}public void setProps(Properties props) {this.props = props;}public Set<String> getSet() {return set;}public void setSet(Set<String> set) {this.set = set;}public String[] getArray() {return array;}public void setArray(String[] array) {this.array = array;}
}

为此可以这样装配这些属性。

<bean id="complex" class="Juice.main.pojo.complex"><property name="id" value="1" /><property name="list"><list><value>value-list-1</value><value>value-list-2</value><value>value-list-3</value></list></property><property name="map"><map><entry key="key1" value="value-key-1" /><entry key="key2" value="value-key-2" /><entry key="key3" value="value-key-3" /></map></property><property name="props"><props><prop key="prop1">value-prop-1</prop><prop key="prop1">value-prop-2</prop><prop key="prop1">value-prop-3</prop></props></property><property name="set"><set><value>value-set-1</value><value>value-set-2</value><value>value-set-3</value></set></property><property name="array"><array><value>value-array-1</value><value>value-array-2</value><value>value-array-3</value></array></property></bean>

当然这里的装配主要集中在比较简单的String类型上,其主要的目的是告诉大家如何装配简易的数据到集合中。
从上面可以看到对字符串的各个集合的装载,但是有些时候可以需要更为复杂的装载,比如一个list可以是一个系列类的对象,又如一个Map集合类,键可以是一个类对象,而值也是一个类对象。为此,我们再来举一个简单的例子。

public class Role {private Long id;private String roleName;private String note;
}public class User {private Long id;private String userName;private String note;
}public class UserRoleAdd {private Long id;private List<Role> list;private Map<Role,User> map;private Set<Role> set;
}

这里可以看到,对于List、Map和Set等集合类使用的是类对象,不过不用担心,Spring IoC容器提供了对应的配置方法,代码如下:

<bean id="role1" class="Juice.main.pojo.Role"><property name="id" value="1" /><property name="roleName" value="role_name_1" /><property name="note" value="role_note_1" /></bean><bean id="role2" class="Juice.main.pojo.Role"><property name="id" value="2" /><property name="roleName" value="role_name_2" /><property name="note" value="role_note_2" /></bean><bean id="user1" class="Juice.main.pojo.User"><property name="id" value="1" /><property name="userName" value="user_name_1" /><property name="note" value="user_note_1" /></bean><bean id="user2" class="Juice.main.pojo.User"><property name="id" value="2" /><property name="userName" value="user_name_2" /><property name="note" value="user_note_2" /></bean><bean id="userRoleAdd" class="Juice.main.pojo.UserRoleAdd"><property name="id" value="1" /><property name="list"><list><ref bean="role1" /><ref bean="role2" /></list></property><property name="map"><map><entry key-ref="role1" value-ref="user1" /><entry key-ref="role2" value-ref="user2" /></map></property><property name="set"><set><ref bean="role1" /><ref bean="role2" /></set></property></bean>

这里先定义了两个角色Bean(role1和role2)和两个用户(user1和user2),它们和之前的定义并没有什么不同,只是后面的定义稍微不一样。

命名空间装配

除了上述的配置之外,Spring还提供了对应的命名空间的定义,只是在使用命名空间的时候要先引入对应的命名空间和XML模式。比如我们用这个模式来定义userRoleAdd类实例。

<?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:c="http://www.springframework.org/schema/c"xmlns:p="http://www.springframework.org/schema/p"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"><bean id="role1" class="Juice.main.pojo.Role"c:_0="1" c:_1="role_name_1" c:_2="role_note_1" /><bean id="role2" class="Juice.main.pojo.Role"p:id="2" p:roleName="role_name_2" p:note="role_note_2" /><bean id="user1" class="Juice.main.pojo.User"p:id="1" p:userName="user_name_1" p:note="user_note_1" /><bean id="user2" class="Juice.main.pojo.User"p:id="2" p:userName="user_name_2" p:note="user_note_2" /><util:list id="list"><ref bean="role1" /><ref bean="role2" /></util:list><util:map id="map"><entry key-ref="role1" value-ref="user1" /><entry key-ref="role2" value-ref="user2" /></util:map><util:set id="set"><ref bean="role1" /><ref bean="role2" /></util:set><bean id="userRoleAdd" class="Juice.main.pojo.UserRoleAdd"p:id="1" p:list-ref="list" p:map-ref="map" p:set-ref="set" />
</beans>

通过注解配置装配Bean

在大多时候,我们会考虑使用注解(annotation)的方式去装配Bean。

1、使用@Component装配Bean

首先定义一下POJO,代码如下:

@Component(value = "role")
public class Role {@Value("1")private Long id;@Value("role_name_1")private String roleName;@Value("role_note_1")private String note;
}

解释一下上面的注解:

  • 注解@Component代表Spring IoC会把这个类扫描生成Bean实例,而其中的value属性代表这个类在Spring中的id,这相当于XML方式定义的Bean的id,也可以简写成@Component(“role”)。
  • 注解@Value代表的是值的注入。

现在有了这个类,但是还不能进行测试,因为Spring IoC并不知道需要去哪里扫描对象,这个时候可以使用一个Java Config 来告诉它,代码如下:

@ComponentScan
public class PojoConfig {}

这个类十分简单,几乎没有什么逻辑

  • 包名要和上面类的包名保持一致
  • @ComponentScan代表进行扫描,默认是扫描当前包的路径,POJO的包名和它保持一致才能扫描,否则是没有的。

这样之后我们就可以进行测试:

package Juice.test;import Juice.main.pojo.PojoConfig;
import Juice.main.pojo.Role;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class AnnotationMain {public static void main(String[] args){ApplicationContext context=new AnnotationConfigApplicationContext(PojoConfig.class);Role role=context.getBean(Role.class);System.out.println(role.getId());}
}

@ComponentScan存在着两个配置项:第一个是basePackages,它可以配置一个Java包的数组,Spring会根据它的配置扫描对应的包和子包,将配置好的Bean装配起来;第二个是basePackageClasses,它可以配置多个类,Spring会根据配置的类所在的包,为包和子包进行扫描装配对于配置的Bean。

2、自动装配——@Autowired

@Autowired主要是注解注入对象,关于这个问题,在注解中略微有点复杂,在大部分情况下建议使用自动装配,因为这样可以减少配置的复杂度。
下面我们来测试自动装配。

package Juice.main.service;import Juice.main.pojo.Role;public interface RoleService {public void printRoleInfo(Role role);
}

这个接口采用了Spring推荐的接口方式,这样可以更为灵活,因为这样可以将定义和实现分离,接下来是其实现类,代码如下:

package Juice.main.service.impl;import Juice.main.pojo.Role;
import Juice.main.service.RoleService2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component("RoleService2")
public class RoleServiceImpl2 implements RoleService2 {@Autowiredprivate Role role=null;public Role getRole() {return role;}public void setRole(Role role) {this.role = role;}@Overridepublic void printRoleInfo() {System.out.println("id="+role.getId());System.out.println("roleName="+role.getRoleName());System.out.println("note="+role.getNote());}
}

这里的@Autowired注解,表示在Spring IoC定位所有的Bean后,这个字段需要按类型注入,这样IoC容器就会寻找资源,然后将其注入。

@Autowired出来可以配置在属性之外,还允许方法配置,常见的Bean的setting方法也可以使用它来完成注入。
在大部分情况下,我还是建议使用@Autowired注解,这是Spring IoC自动装配完成的,是的配置大幅度减少,满足约定优于配置的原则,增强程序的健壮性。

3、@Primary和@Qualifier

@Autowired注解可以完成一些自动装配的功能,并且方法十分简单,但是有时候这样的方式并不能使用。因为该注解采用的是按类型来注入对象,但是Java中接口可以有多个实现类,这样就会造成通过类型获取Bean的不唯一,从而导致Spring IoC类似于按类型的方式无法获取得到唯一的实例化类。
为了解决这一方法,才推出了@Primary和@Qualifier这两个注解。

注解@Primary
注解@Primary代表首要的,当Spring IoC通过一个接口或者抽象类注入对象时,注解@Primary会告诉Spring IoC容器,请优先使用该类注入。
但是无论如何这个接口只能解决首要性问题,而不能解决选择性的问题,简而言之,他不能选择使用接口具体的实现类去注入。

注解@Qualifier
注解@Qualifier就好比是采用按名称查找的方法。

@Autiwired
@Qualifier("roleService")
private RoleService roleService=null;

4、使用@Bean装配Bean
对于Java而言,大部分的开发都需要引入第三方的包,而且往往并没有这些包的源码,这时候将无法为这些包的类加入@Component注解,让它们变为开发环境的Bean。
这个时候Spring给予了一个注解@Bean,它可以注解到方法之上,并且将方法返回的对象作为Spring的Bean,存放在IoC容器中。

@Bean(name="dataSource")
public DataSource getDataSource(){...
}

这样就能装配一个Bean,当Spring IoC容器扫描它的时候,就会为其生成对应的Bean。这里还配置了Bean的name为dataSource,这就意味着Spring生成该Bean的时候就会使用dataSource作为其BeanName。

2.4.3 Spring表达式(Spring EL)

Spring还提供了更灵活的注入方式——Spring表达式。Spring EL拥有很多功能:

  • 使用Bean的id来引用Bean。
  • 调用指定对象的方法和访问对象的属性。
  • 进行运算。
  • 提供正则表达式进行比配。
  • 集合配置。

Bean的属性和方法

使用注解的方式需要用到注解@Value,在属性文件的读取中使用的是“$”,而在Spring EL中则使用“#”。下面我们以角色类为例进行分析,代码如下:


@Component(value = "role")
public class Role {@Value("#{1}")private Long id;@Value("#{role_name_1}")private String roleName;@Value("#{role_note_1}")private String note;
}

这样就可以定义一个BeanName为role的角色类,同时给予它所有的属性赋值,这个时候可以通过另外一个Bean去引用它的属性或者调用它的方法,比如先建一个类——ELBean类,代码如下:

@Component("elBean")
public class ELBean {//通过beanName获取bean,然后注入@Value("#{role}")private Role role;//获取bean的属性id@Value("#{role.id}")private Long id;//调用bean的getNote方法,获取角色名称@Value("#{role.getNote().toString()}")private String note;}

使用类的静态常量和方法

有时候我们可能希望使用一些静态方法和常量,比如圆周率Π,而在Java中就是Math类的PI常量,如果需要注入它,代码如下:

@Value("#{T(Math).PI}")
private double pi;

同样的,有时候需要使用Math类的静态方法去生产随机数,这个时候就需要使用它的random方法,代码如下:

@Value("#{T(Math).random()}")
private double random;

这样就可以通过调用类的静态方法加载对应的数据了。

Spring EL运算
Spring EL还可以进行运算,比如在ELBean上增加一个数字num,其值默认为要求是角色编号(id)+1,那么我们可以这么写:

@Value("#{role.id+1}")
private int num;

有时候“+”运算符也可以运用在字符串的连接上,代码如下:

@Value("#{role.roleName+role.note}")
private String str;

这样就能够得到一个角色名称和备注连接的字符串。
比较两个值是否相等,还有其他更多的比较,比如大于、小于等。

@Value("#{role.id==1}")
private boolean equalNum;@Value("#{role.note eq 'note_1'}")
private boolean equalString;@Value("#{role.id>2}")
private boolean greater;

在Java中,也许你会怀旧三目运算,我们也可以去实现这样的功能

@Value("#{role.id>1 ? 5:1}")
private int max;@Value("#{role.note? : 'hello'}")
private String defaultString;
2.4.4 Bean的作用域

在这里插入图片描述
几种作用域中,request、session作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于web的Spring ApplicationContext环境。

Singleton(单例模式)
当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

 <bean id="ServiceImpl" class="com.learn.spring.service.ServiceImpl" scope="singleton">

Prototype(原型模式)
当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

 <bean id="account" class="com.learn.spring.DefaultAccount" scope="prototype"/>  或者<bean id="account" class="com.learn.spring.DefaultAccount" singleton="false"/>

3、Java的反射机制

Java反射技术应用广泛,它能够配置:类的全限定名、方法和参数。完成对象的初始化以及发射某些方法。在Java中,反射是通过包java.lang.reflect.*来实现的。
今天我主要讲解对象构建(包括没有参数的和有参数的构造方法)和方法的发射调用。

1、通过反射构造方法
在Java中允许通过发射配置信息构建对象,下面我先写一个简单的ReflectServiceImpl类,代码如下:

public class ReflectServiceImpl {public void sayHello(String name) {System.err.println("Hello! "+name);}
}

然后通过发射的方法去构建它,代码如下:

//通过反射构造ReflectServiceImpl类的对象
public ReflectServiceImpl getInstance() {ReflectServiceImpl object=null;try {object=(ReflectServiceImpl)Class.forName("java发射.src.ReflectServiceImpl").newInstance();}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}return object;}

上面的代码就是生成一个对象,然后将其返回。
object=(ReflectServiceImpl)Class.forName(“java发射.src.ReflectServiceImpl”).newInstance();这段代码的目的就是给类加载器注册了一个类ReflectServiceImpl的全限定名,然后通过newInstance方法初始化了一个类对象。

但是又有了新的问题,如果这个类的构造方法中都至少存在一个参数,如何去反射构建它。在java中,只要稍微改变一下就可以了。下面我把上面的ReflectServiceImpl类进行简单的修改,代码如下:

public class ReflectServiceImpl2 {private String name;public ReflectServiceImpl2(String name) {this.name=name;}public void sayHello(String name) {System.err.println("Hello! "+name);}
}

这里实现了含一个参数的构造方法,这时将不能用之前的办法将其反射生成对象,而也要相应的做一些修改,代码如下:

//通过反射构造ReflectServiceImpl2类的对象public ReflectServiceImpl2 getInstance2() {ReflectServiceImpl2 object=null;try {object=(ReflectServiceImpl2)Class.forName("java发射.src.ReflectServiceImpl2").getConstructor(String.class).newInstance("monkey");}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}return object;}

先通过forName加载到类的加载器。然后通过getConstructor方法,它的参数可以是多个的,这里定义为String.class,意为有且只有一个参数类型为String的构建方法。通过这个方法可以对重名方法进行排除,此时再用newInstance方法生成对象,只是newInstance方法也多了一个参数(monkey)。实际上就等于

object=new ReflectServiceImpl2("monkey");

反射的优点:只要配置就可以生成对象,可以解除程序的耦合度,比较灵活。
反射的缺点:运行比较慢。

2、反射方法
在使用反射方法前要获取方法对象,得到了方法才能够去反射。

//反射ReflectServiceImpl类的sayHello方法public Object reflectMethod() {Object returnObj=null;ReflectServiceImpl target=new ReflectServiceImpl();try {Method method=ReflectServiceImpl.class.getMethod("sayHello", String.class);returnObj=method.invoke(target, "monkey");}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}return returnObj;}

我们来看一下try里面的内容,当有具体的对象target,而不知道具体是哪一个类时,也可以使用如下代码:

Method method=target.getClass().getMethod("sayHello", String.class);

其中第一个参数是方法的名称,第二个参数是参数类型,其实是一个列表,多个参数可以继续编写多个类型,这样便能够获取反射的方法对象。反射方法是运用returnObj=method.invoke(target, “monkey”);代码完成的,第一个参数为target,就是确定用哪个对象调用方法,而monkey就是参数,这行就等同于

target.sayHello("monkey");

3、实例

public Object reflect() {ReflectServiceImpl object=null;try {object=(ReflectServiceImpl)Class.forName("java发射.src.ReflectServiceImpl").newInstance();Method method=ReflectServiceImpl.class.getMethod("sayHello", String.class);method.invoke(object, "monkey");}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}return object;}

这样就能反射对象和方法,测试结果如下:

Hello!monkey

4、Java的动态代理

动态代理的意义在于生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问。
有人可能不知道什么叫做代理模式?
那么我就用一个十分简单的场景来介绍一下。假设你的公司是一家软件设备,你是一位软件工程师。客户带着需求去找公司显然不会直接和你交谈,而是去找你的商务谈,此时客户会认为商务代表公司。
那么客户就是调用者,商务就是代理对象,软件工程师就是真实对象。
显然客户是通过商务去访问软件工程师的,那么商务的意义在于什么呢?
商务可以进行谈判。商务也有可能在开发软件之前谈判失败,此时商务就会根据公司规则去结束和客户的合作关系,这些都不用软件工程师来处理。因此,代理的作用就是,在真实对象访问前或者之后加入对应的逻辑,或者根据其他规则控制是否使用真实对象。
由此我们可以知道代理必须分为两个步骤:

  • 代理对象和真实对象建立代理关系
  • 实现代理对象的代理逻辑方法

今天我主要来讲一讲JDK的动态代理。
JDK动态代理是java.lang.reflect.*包提供的方式,它必须接助一个接口才能产生代理对象。
所以先定义接口,代码如下:

public interface HelloWorld {public void sayHelloWorld();
}

然后提供实现类HelloWorldImpl来实现接口,代码如下:

public class HelloWorldImpl implements HelloWorld{@Overridepublic void sayHelloWorld() {System.out.println("Hello World");}
}

这是最简单的Java接口和实现类的关系,此时可以开始动态代理了。按照我们之前的分析,先要建立起代理对象和真实对象的关系,然后实现代理逻辑。
在JDK动态代理中,要实现代理逻辑类必须去实现java.lang.reflect.InvocationHandler接口,他里面定义了一个invoke()方法,并提供接口数组用于下挂代理对象,代码如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class JdkProxyExample implements InvocationHandler{//真实对象private Object target=null;/** 建立代理对象和真实对象的代理关系,并返回代理对象* @param target 真实对象* @return  代理对象*/public Object bind(Object target) {this.target=target;Object proxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);return proxy;}/** 代理方法逻辑* @param proxy 代理对象* @param method 当前调度方法* @param args 当前方法参数* @return 代理结果返回*/@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws Throwable{System.out.println("进入代理方法");System.out.println("在调度真实对象之前的服务");Object obj=method.invoke(target, args);System.out.println("在调度真实对象之后的服务");return obj;}
}

第一步,建立代理对象和真实对象的关系。
这里是使用了bind方法去完成的。方法里面首先用类的属性target保存了真实对象,然后通过如下语句建立并生成代理对象。

Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);

其中newProxyInstance方法包含3个参数:

  • 第一个是类加载器,我们采用了target本身的类加载器。
  • 第二个是把生成的动态代理对象挂在哪些接口下,这个写法就是放在target实现的接口下。
  • 第三个是定义实现方法逻辑的代理类,this表示当前对象,它必须实现InvocationHandler接口的invoke方法,它就是代理逻辑方法的现实方法。

第二步,实现代理逻辑方法。
invoke方法可以实现代理逻辑,invoke方法的3个参数的含义如下。
proxy:代理对象,就是bind方法生成的对象。
method:当前调度的方法。
args:调度方法的参数。

当我们使用了代理对象调度方法后,他就会进入到invoke方法里面。

Object obj=method.invoke(target, args);

这行代码相当于调度真实对象的方法,这里是通过反射实现。

最后我们再来编写一个测试JDK动态代理,代码如下:

public class testJdkProxy {JdkProxyExample jdk=new JdkProxyExample();HelloWorldImpl hwImpl=new HelloWorldImpl();//绑定关系,代理对象和真实对象之间的关系,因为挂在HelloWorld下,//所以声明代理对象HelloWorld hWorldHelloWorld hWorld=(HelloWorld)jdk.bind(hwImpl);//此时HelloWorld对象已经是代理对象,他会进入代理的逻辑方法invoke里hWorld.sayHelloWorld();
}

测试结果如下:

进入代理逻辑方法
在调度真实对象之前的服务
Hello World
在调度真实对象之后的服务

5、Spring AOP

5.1 什么是AOP

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

5.2 AOP的一些术语

1、切面(Aspect)

切面就是在一个怎样的环境中工作。它可以定义后面需要介绍的各类通知、切点和引入等内容,然后SpringAOP会将其定义的内容织入到约定的流程中,在动态代理中可以把它理解成一个拦截器。

2、通知(Advice)

通知是切面开启后,切面的方法。他根据在代理对象真实方法调用前、后的顺序和逻辑区分。

  • 前置通知(before):在动态代理反射原有对象方法或者执行环绕通知前执行的通知功能。
  • 后置通知(after):在动态代理反射原有对象方法或者执行环绕通知后执行的通知功能。无论是否抛出异常,他都会被执行。
  • 返回通知(afterReturning):在动态代理反射原有对象方法或者执行环绕通知后正常返回(无异常)执行的通知功能。
  • 异常通知(afterThrowing):在动态代理反射原有对象方法或者执行环绕通知产生异常后执行的通知功能。
  • 环绕通知(around):在动态代理中,他可以取代当前被拦截对象的方法,提供回调原有被拦截对象的方法。

3、引入(introduction)

引入允许我们在现有的类里添加自定义的类和方法。

4、切点(Pointcut)

这是一个告诉Spring AOP在什么时候启动拦截并织入对应的流程中,因为并不是所有的开发都需要启动AOP的,他往往通过正则表达式进行限定。

5、连接点(join point)

连接点对应的是具体需要拦截的东西,比如通过切点的正则表达式去判断那些方法是连接点,从而织入对应的通知。

6、织入(Wearing)

织入是一个生成代理对象并将切面内容放入到流程中的过程。实际代理的方法分为静态代理和动态代理。静态代理是在编译class文件时生成的代码逻辑,但是在Spring中并不使用这样的方式,所以我们暂时不讨论。一种是通过ClassLoader也就是在类加载的时候生成的代码逻辑,但是它在应用程序代码运行之前就生成了对应的逻辑。还有一种是运行期,动态生成代码的方式,这是SpringAOP所采用的方式,Spring是以JDK和CGLIB动态代理来生成代理对象的。

在这里插入图片描述

5.3 使用Spring实现AOP

5.3.1 通过 Spring API 实现

首先编写我们的业务接口和实现类

public interface UserService {public void add();public void delete();public void update();public void search();}
public class UserServiceImpl implements UserService{@Overridepublic void add() {System.out.println("增加用户");}@Overridepublic void delete() {System.out.println("删除用户");}@Overridepublic void update() {System.out.println("更新用户");}@Overridepublic void search() {System.out.println("查询用户");}
}

然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强

public class Log implements MethodBeforeAdvice {//method : 要执行的目标对象的方法//objects : 被调用的方法的参数//Object : 目标对象@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");}
}
public class AfterLog implements AfterReturningAdvice {//returnValue 返回值//method被调用的方法//args 被调用的方法的对象的参数//target 被调用的目标对象@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args,Object target) throws Throwable {System.out.println("执行了" + target.getClass().getName()+"的"+method.getName()+"方法,"+"返回值:"+returnValue);}
}

最后去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"><!--注册bean--><bean id="userService" class="com.learn.spring.service.UserServiceImpl"/><bean id="log" class="com.learn.spring.log.Log"/><bean id="afterLog" class="com.learn.spring.log.AfterLog"/><!--aop的配置--><aop:config><!--切入点 expression:表达式匹配要执行的方法--><aop:pointcut id="pointcut" expression="execution(* com.learn.spring.service.UserServiceImpl.*(..))"/><!--执行环绕; advice-ref执行方法 . pointcut-ref切入点--><aop:advisor advice-ref="log" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/></aop:config></beans>

测试

public class MyTest {@Testpublic void test(){ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");UserService userService = (UserService) context.getBean("userService");userService.search();}
}

Aop的重要性 : 很重要 . 一定要理解其中的思路 , 主要是思想的理解这一块 .

Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理 。

5.3.2 自定义类来实现Aop

目标业务类不变依旧是userServiceImpl

第一步 : 写我们自己的一个切入类

public class DiyPointcut {public void before(){System.out.println("---------方法执行前---------");}public void after(){System.out.println("---------方法执行后---------");}}

去spring中配置

<!--第二种方式自定义实现-->
<!--注册bean-->
<bean id="diy" class="com.kuang.config.DiyPointcut"/><!--aop的配置-->
<aop:config><!--第二种方式:使用AOP的标签实现--><aop:aspect ref="diy"><aop:pointcut id="diyPonitcut" expression="execution(* com.learn.spring.service.UserServiceImpl.*(..))"/><aop:before pointcut-ref="diyPonitcut" method="before"/><aop:after pointcut-ref="diyPonitcut" method="after"/></aop:aspect>
</aop:config>

测试:

public class MyTest {@Testpublic void test(){ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");UserService userService = (UserService) context.getBean("userService");userService.add();}
}
5.3.3 使用@AspectJ注解开发SpringAOP

现在使用@AspectJ注解的方式已经成为了主流。所以我用一个简单的例子来了解一下他的整个过程。

选择连接点
Spring是方法级别的AOP框架,我们主要是以某个类的某个方法作为连接点,用动态代理的理论来说,就是要拦截哪个方法织入对应AOP通知。
首先我们建一个接口:

package aop.service;import game.bigLiZi.game.pojo.Role;public interface RoleService {public void printRole(Role role);
}

这个接口很简单,接下来提供一个实现类:

package aop.service.impl;import aop.service.RoleService;
import game.bigLiZi.game.pojo.Role;
import org.springframework.stereotype.Component;@Component
public class RoleServiceImpl implements RoleService {@Overridepublic void printRole(Role role) {System.out.println("{ id:"+role.getId()+"roleName:"+role.getRoleName()+"note:"+role.getNote()+"}");}
}

这个时候如果把printRole作为AOP的连接点,那么用动态代理的语言就是要为类RoleServiceImpl生成代理对象,然后拦截printRole方法,于是可以产生各种AOP通知方法。

创建切面
选择好了连接点就可以创建切面了,在Spring中只要使用@Aspect注解一个类,那么Spring IoC容器就会认为这是一个切面了。

package aop.aspect;import org.aspectj.lang.annotation.*;@Aspect
public class RoleAspect {@Before("execution(* aop.service.impl.RoleServiceImpl.printRole(..))")public void before(){System.out.println("before..........");}@After("execution(* aop.service.impl.RoleServiceImpl.printRole(..))")public void after(){System.out.println("after..........");}@AfterReturning("execution(* aop.service.impl.RoleServiceImpl.printRole(..))")public void afterReturning(){System.out.println("afterReturning..........");}@AfterThrowing("execution(* aop.service.impl.RoleServiceImpl.printRole(..))")public void afterThrowing(){System.out.println("afterThrowing..........");}
}

这里我们就要说一说AspectJ注解了:

  • @Before:在被代理对象的方法前调用,前置通知。
  • @Around:将被代理对象的方法封装起来,并用环绕通知取代它。 它将覆盖原有方法,但是允许你通过反射调用原有的方法。
  • @After:在被代理对象的方法后调用, 后置通知。
  • @AfterReturning:在被代理对象的方法正常返回后调用,返回通知,要求被代理对象的方法执行过程中没有发生异常。
  • @AfterThrowing:在被代理对象的方法抛出异常后调用,异常通知,要求被代理对象的方法执行过程中返回异常。

上面那段代码的注解使用了对应的正则表达式,这些正则表达式是切点的问题,也就是要告诉Spring AOP,需要拦截什么对象的什么方法。

定义切点
上面代码在注解中定义了execution的正则表达式,Spring是通过这个正则表达式判断是否需要拦截你的方法,这个表达式是:

execution(* aop.service.impl.RoleServiceImpl.printRole(..))

对这个表达式分析一下:

  • execution:代表执行方法的时候会触发
  • *:代表任意返回类型的方法
  • aop.service.impl.RoleServiceImpl:代表类的全限定名
  • printRole:被拦截方法名称
  • (…):任意的参数

上面的表达式还有些简单,AspectJ的指示器还有很多,下面我列举几个:

  • arg():限制连接点匹配参数为指定类型的方法
  • execution:用于匹配连接点的执行方法
  • this():限制连接点匹配AOP代理的Bean,引用为指定类型的类
  • target:限制连接点匹配被代理对象为指定的类型
  • within():限制连接点匹配的包

此外,上面的正则表达式需要重复书写多次,比较麻烦,这里我们可以使用@Pointcut来避免这个麻烦。代码如下:

package aop.aspect;import org.aspectj.lang.annotation.*;public class anotherAspect {@Pointcut("execution(* aop.service.impl.RoleServiceImpl.printRole(..))")public void print(){}@Before("print()")public void before(){System.out.println("before..........");}@After("print()")public void after(){System.out.println("after..........");}@AfterReturning("print()")public void afterReturning(){System.out.println("afterReturning..........");}@AfterThrowing("print()")public void afterThrowing(){System.out.println("afterThrowing..........");}
}

测试AOP
连接点、切面以及切点都有了,这个时候就可以编写测试代码来测试AOP的内容。
首先要对Spring的Bean进行配置,采用Java配置,代码如下:

package aop.config;import aop.aspect.RoleAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration
@EnableAspectJAutoProxy
@ComponentScan("aop")
public class AopConfig {@Beanpublic RoleAspect getRoleAspect(){return new RoleAspect();}
}

测试AOP流程

package aop.main;import aop.config.AopConfig;
import aop.service.RoleService;
import game.bigLiZi.game.pojo.Role;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args){ApplicationContext ctx=new AnnotationConfigApplicationContext(AopConfig.class);RoleService roleService=(RoleService)ctx.getBean(RoleService.class);Role role=new Role();role.setId(1L);role.setRoleName("role_name_1");role.setNote("role_note_1");roleService.printRole(role);System.out.println("########################");role=null;roleService.printRole(role);}
}

在第二次打印之前,将role设置为null,这样是为了测试异常返回通知。

before..........
{ id:1roleName:role_name_1note:role_note_1}
after..........
afterReturning..........
########################
before..........
after..........
afterThrowing..........
Exception in thread "main" java.lang.NullPointerException

6、一个简单的MyBatis-Spring项目

前提:Mybatis-Spring项目不是Spring框架的子项目,所以我们需要自己下载jar包。
具体下载方法:mybatis-spring.1.3.1.jar

配置Mybatis-Spring项目需要以下几步:

  1. 配置数据库
  2. 配置SqlSessionFactory,也可以选择配置SqlSessionTemplate,在同时配置SqlSessionFactory和SqlSessionTemplate的情况下,优先采用SqlSessionTemplate。
  3. 配置Mapper,可以配置单个Mapper,也可以通过扫描的方法生成Mapper,比较灵活。
  4. 事务管理。

下面我按照顺序编写代码。
1、配置数据库

    <!--数据库连接池 --><bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"><property name="username" value="root" /><property name="password" value="123456" /><property name="driverClass" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/ssm" /></bean>

2、配置SqlSessionFactory

SqlSessionFactory是产生SqlSession的基础,因此配置SqlSessionFactory十分关键。在MyBatis-Spring项目中提供了SqlSessionFactoryBean去支持SqlSessionFactory的配置。由于使用了第三方的包,一般而言,我们倾向于XML的配置,代码如下:

<!--配置SqlSessionFactory --><bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="configLocation" value="classpath:sqlMapConfig.xml" /></bean>

这里配置了SqlSessionFactoryBean,但是只配置了数据源,然后引入一个MyBatis配置文件。下面我们来看看配置文件的代码:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><!-- 这个配置使全局的映射器启用或者禁用缓存--><setting name="cacheEnabled" value="true" /><!-- 允许JDBC支持生成的键。需要适当的驱动。如果设置为true,则这个设置强制生成的键被使用--><setting name="useGeneratedKeys" value="true" /><!-- 配置默认的执行器 :SIMPLE执行器没有什么特别之处。REUSE执行器重用预处理语句,BATCH执行器重用语句和批量更新--><setting name="defaultExecutorType" value="REUSE" /><!--全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 --><setting name="lazyLoadingEnabled" value="true" /><!-- 设置超时时间,它决定驱动等待一个数据库相应的时间--><setting name="defaultStatementTimeout" value="25000" /></settings><!-- 别名设置--><typeAliases><typeAlias alias="role" type="firstMybatisSpringActivity.pojo.Role" /></typeAliases><!-- 指定映射器路径--><mappers><mapper resource="firstMybatisSpringActivity/mapper/RoleMapper.xml" /></mappers>
</configuration>

这里通过mapper标签引入了映射器RoleMapper.xml。RoleMapper.xml代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="firstMybatisSpringActivity.mapper.RoleMapper"><insert id="insertRole" useGeneratedKeys="true" keyProperty="id">insert into role(role_name,note) values (#{roleName},#{note})</insert><delete id="deleteRole" parameterType="long">delete from role where id=#{id}</delete><select id="getRole" parameterType="long" resultType="role">select id,role_name as roleName,note from role where id=#{id}</select><update id="updateRole" parameterType="role">update roleset role_name=#{roleName},note=#{note}where id=#{id}</update>
</mapper>

这里定义了一个命名空间——firstMybatisSpringActivity.mapper.RoleMapper,并且提供了对角色的增删改查方法。按照Mybatis的规则定义了一个接口RoleMapper.java,这样才能调用它。代码如下:

package firstMybatisSpringActivity.mapper;import firstMybatisSpringActivity.pojo.Role;
import org.apache.ibatis.annotations.Param;public interface RoleMapper {public int insertRole(Role role);public int deleteRole(@Param("id") Long id);public Role getRole(@Param("id") Long id);public int updateRole(Role role);
}

到这里就完成了关于MyBatis框架的主要代码,但是RoleMapper是一个接口,而不是一个类,它不能产生实例,所以我们要用另外的方法去配置它。

MyBatis-Spring提供了一个MapperFactoryBean类作为中介,我们可以配置它来实现我们想要的Mapper。现在我们来配置RoleMapper的映射器对象。代码如下:

<bean id="roleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"><!-- RoleMapper接口将被扫描为Mapper --><property name="mapperInterface" value="firstMybatisSpringActivity.mapper.RoleMapper" /><property name="SqlSessionFactory" ref="SqlSessionFactory" /></bean>

这里我们可以看到MapperFactoryBean存在3个属性可以配置,分别是mapperInterface、SqlSessionFactory和sqlSessionTemplate,其中:

  • mapperInterface是映射器的接口。
  • 如果同时配置SqlSessionFactory和sqlSessionTemplate,那么他就会启用sqlSessionTemplate,而SqlSessionFactory作废。

这里笔者插一手sqlSessionTemplate组件的介绍。
严格来说,SqlSessionTemplate并不是一个必须配置的组件,但是他也有一定的价值。首先他是线程安全的类,也就是确保每一个线程使用的SqlSession唯一且不互相冲突。其次,它提供了一系列的功能,比如增删改查等常用功能,不过在此之前需要先配置它,代码如下:

	<!-- 配置SqlSessionTemplate--><bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"><constructor-arg ref="SqlSessionFactory" /></bean>

最后我们用代码来测试一下:

package firstMybatisSpringActivity.main;import firstMybatisSpringActivity.mapper.RoleMapper;
import firstMybatisSpringActivity.pojo.Role;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class main {public static void main(String[] args){//ctx为Spring IoC容器ApplicationContext ctx=new ClassPathXmlApplicationContext("spring-config.xml");RoleMapper roleMapper=ctx.getBean(RoleMapper.class);Role role=new Role();role.setRoleName("role_name_mapper");role.setNote("note_mapper");roleMapper.insertRole(role);Long id=role.getId();roleMapper.getRole(id);role.setNote("note_mapper_update");roleMapper.updateRole(role);roleMapper.deleteRole(id);}
}

运行结果:

DEBUG 2020-04-19 21:26:22,739 org.springframework.context.support.AbstractApplicationContext: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@782830e
DEBUG 2020-04-19 21:26:23,044 org.springframework.beans.factory.xml.XmlBeanDefinitionReader: Loaded 5 bean definitions from class path resource [spring-config.xml]
DEBUG 2020-04-19 21:26:23,122 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.mybatis.spring.mapper.MapperScannerConfigurer#0'WARN 2020-04-19 21:26:23,258 org.mybatis.spring.mapper.ClassPathMapperScanner: No MyBatis mapper was found in '[firstMybatisSpringActivity.mapper]' package. Please check your configuration.
DEBUG 2020-04-19 21:26:23,299 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
DEBUG 2020-04-19 21:26:23,320 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
DEBUG 2020-04-19 21:26:23,322 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
DEBUG 2020-04-19 21:26:23,324 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
DEBUG 2020-04-19 21:26:23,326 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
DEBUG 2020-04-19 21:26:23,346 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'dataSource'
DEBUG 2020-04-19 21:26:23,414 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'SqlSessionFactory'
DEBUG 2020-04-19 21:26:23,436 org.apache.ibatis.logging.LogFactory: Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
DEBUG 2020-04-19 21:26:23,653 org.mybatis.spring.SqlSessionFactoryBean: Parsed configuration file: 'class path resource [sqlMapConfig.xml]'
DEBUG 2020-04-19 21:26:23,654 org.mybatis.spring.SqlSessionFactoryBean: Property 'mapperLocations' was not specified or no matching resources found
DEBUG 2020-04-19 21:26:23,657 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'sqlSessionTemplate'
DEBUG 2020-04-19 21:26:23,694 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'roleMapper'
DEBUG 2020-04-19 21:26:23,741 org.mybatis.spring.SqlSessionUtils: Creating a new SqlSession
DEBUG 2020-04-19 21:26:23,752 org.mybatis.spring.SqlSessionUtils: SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e6f74c] was not registered for synchronization because synchronization is not active
DEBUG 2020-04-19 21:26:23,759 org.springframework.jdbc.datasource.DataSourceUtils: Fetching JDBC Connection from DataSource
DEBUG 2020-04-19 21:26:23,760 org.springframework.jdbc.datasource.SimpleDriverDataSource: Creating new JDBC Driver Connection to [jdbc:mysql://localhost:3306/ssm]
DEBUG 2020-04-19 21:26:24,227 org.mybatis.spring.transaction.SpringManagedTransaction: JDBC Connection [com.mysql.jdbc.JDBC4Connection@683dbc2c] will not be managed by Spring
DEBUG 2020-04-19 21:26:24,240 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: insert into role(role_name,note) values (?,?) 
DEBUG 2020-04-19 21:26:24,279 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: role_name_mapper(String), note_mapper(String)
DEBUG 2020-04-19 21:26:24,302 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==    Updates: 1
DEBUG 2020-04-19 21:26:24,304 org.mybatis.spring.SqlSessionUtils: Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e6f74c]
DEBUG 2020-04-19 21:26:24,309 org.mybatis.spring.SqlSessionUtils: Creating a new SqlSession
DEBUG 2020-04-19 21:26:24,309 org.mybatis.spring.SqlSessionUtils: SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@65b3f4a4] was not registered for synchronization because synchronization is not active
DEBUG 2020-04-19 21:26:24,311 org.springframework.jdbc.datasource.DataSourceUtils: Fetching JDBC Connection from DataSource
DEBUG 2020-04-19 21:26:24,311 org.springframework.jdbc.datasource.SimpleDriverDataSource: Creating new JDBC Driver Connection to [jdbc:mysql://localhost:3306/ssm]
DEBUG 2020-04-19 21:26:24,327 org.mybatis.spring.transaction.SpringManagedTransaction: JDBC Connection [com.mysql.jdbc.JDBC4Connection@28975c28] will not be managed by Spring
DEBUG 2020-04-19 21:26:24,327 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select id,role_name as roleName,note from role where id=? 
DEBUG 2020-04-19 21:26:24,328 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 5(Long)
DEBUG 2020-04-19 21:26:24,349 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1
DEBUG 2020-04-19 21:26:24,350 org.mybatis.spring.SqlSessionUtils: Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@65b3f4a4]
DEBUG 2020-04-19 21:26:24,351 org.mybatis.spring.SqlSessionUtils: Creating a new SqlSession
DEBUG 2020-04-19 21:26:24,351 org.mybatis.spring.SqlSessionUtils: SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@55f616cf] was not registered for synchronization because synchronization is not active
DEBUG 2020-04-19 21:26:24,351 org.springframework.jdbc.datasource.DataSourceUtils: Fetching JDBC Connection from DataSource
DEBUG 2020-04-19 21:26:24,351 org.springframework.jdbc.datasource.SimpleDriverDataSource: Creating new JDBC Driver Connection to [jdbc:mysql://localhost:3306/ssm]
DEBUG 2020-04-19 21:26:24,360 org.mybatis.spring.transaction.SpringManagedTransaction: JDBC Connection [com.mysql.jdbc.JDBC4Connection@46fa7c39] will not be managed by Spring
DEBUG 2020-04-19 21:26:24,361 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: update role set role_name=?, note=? where id=? 
DEBUG 2020-04-19 21:26:24,361 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: role_name_mapper(String), note_mapper_update(String), 5(Long)
DEBUG 2020-04-19 21:26:24,364 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==    Updates: 1
DEBUG 2020-04-19 21:26:24,364 org.mybatis.spring.SqlSessionUtils: Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@55f616cf]
DEBUG 2020-04-19 21:26:24,365 org.mybatis.spring.SqlSessionUtils: Creating a new SqlSession
DEBUG 2020-04-19 21:26:24,365 org.mybatis.spring.SqlSessionUtils: SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4a668b6e] was not registered for synchronization because synchronization is not active
DEBUG 2020-04-19 21:26:24,365 org.springframework.jdbc.datasource.DataSourceUtils: Fetching JDBC Connection from DataSource
DEBUG 2020-04-19 21:26:24,365 org.springframework.jdbc.datasource.SimpleDriverDataSource: Creating new JDBC Driver Connection to [jdbc:mysql://localhost:3306/ssm]
DEBUG 2020-04-19 21:26:24,377 org.mybatis.spring.transaction.SpringManagedTransaction: JDBC Connection [com.mysql.jdbc.JDBC4Connection@f381794] will not be managed by Spring
DEBUG 2020-04-19 21:26:24,377 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: delete from role where id=? 
DEBUG 2020-04-19 21:26:24,378 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 5(Long)
DEBUG 2020-04-19 21:26:24,380 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==    Updates: 1
DEBUG 2020-04-19 21:26:24,381 org.mybatis.spring.SqlSessionUtils: Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4a668b6e]

7、在Spring+Mybatis组合中使用事务的简单实例

实例目录图:
在这里插入图片描述
chapter13Spring-cfg.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:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"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/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!-- 启用扫描机制,并制定扫描对应的包 --><context:annotation-config /><context:component-scan base-package="Chapter13.*" /><!-- 数据库连接池 --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/ssm" /><property name="username" value="root" /><property name="password" value="hjw19990825" /><property name="maxActive" value="255" /><property name="maxIdle" value="5" /><property name="maxWait" value="10000" /></bean><!-- 集成MyBatis --><bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><!--指定Mybatis-config.xml --><property name="configLocation" value="classpath:/Chapter13/mybatis/mybatis-config.xml" /></bean><!-- 事务管理器配置数据源事务 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!--使用注解定义事务 --><tx:annotation-driven transaction-manager="transactionManager" /><!-- 采用自动扫描方式创建mapper bean --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="Chapter13" /><property name="SqlSessionFactory" ref="SqlSessionFactory" /><property name="annotationClass" value="org.springframework.stereotype.Repository" /></bean></beans>

Role.java

package Chapter13.pojo;public class Role {private Long id;private String roleName;private String note;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}public String getNote() {return note;}public void setNote(String note) {this.note = note;}public Role(){}
}

搭建MyBatis的映射文件,建立SQL和POJO的关系。

RoleMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="Chapter13.mapper.RoleMapper"><insert id="insertRole" parameterType="Chapter13.pojo.Role">insert into role(role_name,note) values (#{roleName},#{note})</insert></mapper> 

配置一个接口去使用。
RoleMapper.java

package Chapter13.mapper;import Chapter13.pojo.Role;
import org.springframework.stereotype.Repository;@Repository
public interface RoleMapper {public int insertRole(Role role);
}

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><mappers><mapper resource="Chapter13/sqlMapper/RoleMapper.xml" /></mappers>
</configuration>

这样MyBatis部分的内容就配置完成了,接着配置一些服务类(Service)。对于服务类而言,在开发的过程中一般都坚持“接口+实现类”的规则,这有利于实现类的变化。这里我定义了两个接口。

RoleService.java

package Chapter13.service;import Chapter13.pojo.Role;public interface RoleService {public int insertRole(Role role);
}

RoleServiceList.java

package Chapter13.service;import Chapter13.pojo.Role;import java.util.List;public interface RoleListService {public int insertRoleList(List<Role> roleList);
}

然后写两个实现类。

RoleServiceImpl.java

package Chapter13.service.impl;import Chapter13.mapper.RoleMapper;
import Chapter13.pojo.Role;
import Chapter13.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class RoleServiceImpl implements RoleService {@Autowiredprivate RoleMapper roleMapper=null;@Override@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED)public int insertRole(Role role) {return roleMapper.insertRole(role);}
}

RoleListServiceImpl.java

package Chapter13.service.impl;import Chapter13.pojo.Role;
import Chapter13.service.RoleListService;
import Chapter13.service.RoleService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Service
public class RoleListServiceImpl implements RoleListService {@Autowiredprivate RoleService roleService=null;Logger log=Logger.getLogger(RoleListServiceImpl.class);@Override@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)public int insertRoleList(List<Role> roleList) {int count=0;for(Role role:roleList){try{count=roleService.insertRole(role)+1;}catch (Exception ex){log.info(ex);}}return count;}
}

最后我们在编写一个测试类来测试这些事务。

Chapter13Main.java

package Chapter13.main;import Chapter13.pojo.Role;
import Chapter13.service.RoleListService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.ArrayList;
import java.util.List;public class Chapter13Main {public static void main(String[] args){ApplicationContext ctx=new ClassPathXmlApplicationContext("chapter13Spring-cfg.xml");RoleListService roleListService=ctx.getBean(RoleListService.class);List<Role> roleList=new ArrayList<Role>();for(int i=1;i<=2;i++){Role role=new Role();role.setRoleName("role_name_"+i);role.setNote("role_note_"+i);roleList.add(role);}int count=roleListService.insertRoleList(roleList);System.out.println(count);}
}

运行结果:

......
DEBUG 2020-04-22 18:52:30,548 org.mybatis.spring.mapper.ClassPathMapperScanner: Creating MapperFactoryBean with name 'roleMapper' and 'Chapter13.mapper.RoleMapper' mapperInterface
DEBUG 2020-04-22 18:52:30,558 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
DEBUG 2020-04-22 18:52:30,565 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
DEBUG 2020-04-22 18:52:30,572 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory'
DEBUG 2020-04-22 18:52:30,579 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
DEBUG 2020-04-22 18:52:30,595 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
DEBUG 2020-04-22 18:52:30,601 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
DEBUG 2020-04-22 18:52:30,658 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'roleListServiceImpl'
DEBUG 2020-04-22 18:52:30,730 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'roleServiceImpl'
DEBUG 2020-04-22 18:52:30,732 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'roleMapper'
DEBUG 2020-04-22 18:52:30,782 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
DEBUG 2020-04-22 18:52:30,788 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0'
DEBUG 2020-04-22 18:52:30,835 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'transactionManager'
DEBUG 2020-04-22 18:52:30,869 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry: Creating shared instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
DEBUG 2020-04-22 18:52:30,954 org.springframework.transaction.support.AbstractPlatformTransactionManager: Creating new transaction with name [Chapter13.service.impl.RoleListServiceImpl.insertRoleList]: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED
DEBUG 2020-04-22 18:52:31,782 org.springframework.jdbc.datasource.DataSourceTransactionManager: Acquired Connection [org.apache.commons.dbcp.PoolableConnection@28261e8e] for JDBC transaction
DEBUG 2020-04-22 18:52:31,787 org.springframework.jdbc.datasource.DataSourceUtils: Changing isolation level of JDBC Connection [org.apache.commons.dbcp.PoolableConnection@28261e8e] to 2
DEBUG 2020-04-22 18:52:31,789 org.springframework.jdbc.datasource.DataSourceTransactionManager: Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@28261e8e] to manual commit
DEBUG 2020-04-22 18:52:31,791 org.springframework.transaction.support.AbstractPlatformTransactionManager: Suspending current transaction, creating new transaction with name [Chapter13.service.impl.RoleServiceImpl.insertRole]
DEBUG 2020-04-22 18:52:31,803 org.springframework.jdbc.datasource.DataSourceTransactionManager: Acquired Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] for JDBC transaction
DEBUG 2020-04-22 18:52:31,803 org.springframework.jdbc.datasource.DataSourceUtils: Changing isolation level of JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] to 2
DEBUG 2020-04-22 18:52:31,804 org.springframework.jdbc.datasource.DataSourceTransactionManager: Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] to manual commit
DEBUG 2020-04-22 18:52:31,811 org.mybatis.spring.SqlSessionUtils: Creating a new SqlSession
DEBUG 2020-04-22 18:52:31,818 org.mybatis.spring.SqlSessionUtils: Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@76494737]
DEBUG 2020-04-22 18:52:31,828 org.mybatis.spring.transaction.SpringManagedTransaction: JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] will be managed by Spring
DEBUG 2020-04-22 18:52:31,837 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: insert into role(role_name,note) values (?,?) 
DEBUG 2020-04-22 18:52:31,888 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: role_name_1(String), role_note_1(String)
DEBUG 2020-04-22 18:52:31,892 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==    Updates: 1
DEBUG 2020-04-22 18:52:31,893 org.mybatis.spring.SqlSessionUtils: Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@76494737]
DEBUG 2020-04-22 18:52:31,893 org.mybatis.spring.SqlSessionUtils$SqlSessionSynchronization: Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@76494737]
DEBUG 2020-04-22 18:52:31,894 org.mybatis.spring.SqlSessionUtils$SqlSessionSynchronization: Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@76494737]
DEBUG 2020-04-22 18:52:31,894 org.mybatis.spring.SqlSessionUtils$SqlSessionSynchronization: Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@76494737]
DEBUG 2020-04-22 18:52:31,894 org.springframework.transaction.support.AbstractPlatformTransactionManager: Initiating transaction commit
DEBUG 2020-04-22 18:52:31,894 org.springframework.jdbc.datasource.DataSourceTransactionManager: Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@353352b6]
DEBUG 2020-04-22 18:52:31,897 org.springframework.jdbc.datasource.DataSourceUtils: Resetting isolation level of JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] to 4
DEBUG 2020-04-22 18:52:31,898 org.springframework.jdbc.datasource.DataSourceTransactionManager: Releasing JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] after transaction
DEBUG 2020-04-22 18:52:31,899 org.springframework.transaction.support.AbstractPlatformTransactionManager: Resuming suspended transaction after completion of inner transaction
DEBUG 2020-04-22 18:52:31,899 org.springframework.transaction.support.AbstractPlatformTransactionManager: Suspending current transaction, creating new transaction with name [Chapter13.service.impl.RoleServiceImpl.insertRole]
DEBUG 2020-04-22 18:52:31,900 org.springframework.jdbc.datasource.DataSourceTransactionManager: Acquired Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] for JDBC transaction
DEBUG 2020-04-22 18:52:31,900 org.springframework.jdbc.datasource.DataSourceUtils: Changing isolation level of JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] to 2
DEBUG 2020-04-22 18:52:31,900 org.springframework.jdbc.datasource.DataSourceTransactionManager: Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] to manual commit
DEBUG 2020-04-22 18:52:31,901 org.mybatis.spring.SqlSessionUtils: Creating a new SqlSession
DEBUG 2020-04-22 18:52:31,901 org.mybatis.spring.SqlSessionUtils: Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@710636b0]
DEBUG 2020-04-22 18:52:31,901 org.mybatis.spring.transaction.SpringManagedTransaction: JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] will be managed by Spring
DEBUG 2020-04-22 18:52:31,902 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: insert into role(role_name,note) values (?,?) 
DEBUG 2020-04-22 18:52:31,902 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: role_name_2(String), role_note_2(String)
DEBUG 2020-04-22 18:52:31,903 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==    Updates: 1
DEBUG 2020-04-22 18:52:31,903 org.mybatis.spring.SqlSessionUtils: Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@710636b0]
DEBUG 2020-04-22 18:52:31,903 org.mybatis.spring.SqlSessionUtils$SqlSessionSynchronization: Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@710636b0]
DEBUG 2020-04-22 18:52:31,904 org.mybatis.spring.SqlSessionUtils$SqlSessionSynchronization: Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@710636b0]
DEBUG 2020-04-22 18:52:31,904 org.mybatis.spring.SqlSessionUtils$SqlSessionSynchronization: Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@710636b0]
DEBUG 2020-04-22 18:52:31,904 org.springframework.transaction.support.AbstractPlatformTransactionManager: Initiating transaction commit
DEBUG 2020-04-22 18:52:31,904 org.springframework.jdbc.datasource.DataSourceTransactionManager: Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@353352b6]
DEBUG 2020-04-22 18:52:31,906 org.springframework.jdbc.datasource.DataSourceUtils: Resetting isolation level of JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] to 4
DEBUG 2020-04-22 18:52:31,906 org.springframework.jdbc.datasource.DataSourceTransactionManager: Releasing JDBC Connection [org.apache.commons.dbcp.PoolableConnection@353352b6] after transaction
DEBUG 2020-04-22 18:52:31,907 org.springframework.transaction.support.AbstractPlatformTransactionManager: Resuming suspended transaction after completion of inner transaction
DEBUG 2020-04-22 18:52:31,907 org.springframework.transaction.support.AbstractPlatformTransactionManager: Initiating transaction commit
DEBUG 2020-04-22 18:52:31,907 org.springframework.jdbc.datasource.DataSourceTransactionManager: Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@28261e8e]
DEBUG 2020-04-22 18:52:31,908 org.springframework.jdbc.datasource.DataSourceUtils: Resetting isolation level of JDBC Connection [org.apache.commons.dbcp.PoolableConnection@28261e8e] to 4
DEBUG 2020-04-22 18:52:31,908 org.springframework.jdbc.datasource.DataSourceTransactionManager: Releasing JDBC Connection [org.apache.commons.dbcp.PoolableConnection@28261e8e] after transaction
2Process finished with exit code 0
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Qt数据库常用操作(二)

    1、多个筛选条件select *from orderform where name = %1 and age = %2"2、多个更新内容update orderform set class = %1,score = %2 where name = %3 and age= %4"3、事务操作db.transaction() // 开始事务操作 db.commit() //提交 db.rollback() //回滚4…...

    2024/4/27 7:40:38
  2. Netty之旅:你想要的NIO知识点,这里都有!

    前言这段时间也一直在学习Netty相关知识,因为涉及知识点比较多,也走了不少弯路。目前网上关于Netty学习资料玲琅满目,不知如何下手,其实大家都是一样的,学习方法和技巧都是总结出来的,我们在没有找到很好的方法之前不如按部就班先从基础开始,一般从总分总的渐进方式,既…...

    2024/5/1 1:13:53
  3. 类和动态内存分配 默认复制构造函数 默认的赋值运算符 = 在构造函数中使用new时应注意的事项 有关返回对象的说明 成员初始化列表

    ...

    2024/4/29 21:05:11
  4. 数字货币的负责人又开始发言了

    Visa加密负责人库伊谢菲尔德(Cuy Sheffield)在推特上提出了一个问题:如果你现在16岁,能够以自由开发者或设计师的身份在互联网上赚钱,而且希望能在无需父母同意和控制的情况下获得客户支付的报酬,并且尝试储蓄、投资和花费自己的前,你会使用什么金融服务呢?对于这个问题…...

    2024/4/30 22:17:02
  5. Uncaught SyntaxError: Unexpected token ‘.‘错误解决

    解析错误原因Uncaught SyntaxError: Unexpected token .当你遇到这个错误时,首先翻译看他什么意思: Uncaught SyntaxError:意外的标记“.” 小二非常菜,这种问题甚至都是第一次见。(小声bb:可能以前见过忘了) 现在我可以很负责任的告诉大家, 遇到SyntaxError,一定是js的…...

    2024/4/15 20:42:42
  6. 新建一个react项目

    1、安装node.js 官网地址 2、安装npm npm安装较慢,建议更换淘宝源,或者安装cnpm npm install -g cnpm --registry=https://registry.npm.taobao.org 3、安装yarn cnpm install -g yarn 4.创建react项目安装脚手架cnpm install -g create-react-app 或者 npm install -g crea…...

    2024/4/29 22:14:51
  7. Vue从零开始(3):创建页面+添加路由+Mock模拟数据

    前言本来这篇想讲讲怎么打包项目的,但是刚好最近在做一个后台维护的前端项目,然后想想打包这部分可以往后放一放,可以先通过这个项目讲一讲怎么创建页面、添加路由然后如何使用Mock模拟数据。上一篇大家对于Vue CLI搭建脚手架有了一些了解,这篇介绍一款比较容易上手的企业级…...

    2024/5/1 1:25:19
  8. (三)小程序 bindtap 和 catchtap

    区别:bindtap 有事件冒泡 catchtap 没有事件冒泡(1)bindtap<view hover-class="import" bindtap="getTarget">parent<view bindtap="getTarget">children</view></view>点击子元素,会触发自己以及父元素的点击事件 …...

    2024/4/30 19:17:24
  9. 8- app如何修改包名

    8- app如何修改包名其实这个还真的挺简单; 我们都知道, 1- 包名相同,直接覆盖(签名相同) 2- 包名不同,两个应用 所以为了比较版本不同,测试比较方便就需要在同一个手机上安装两个不同版本的同一个APP; 如何解决:让他两的包名不同就可以了; 改变包名—》两步走:1- ra…...

    2024/4/30 22:07:39
  10. 【路径学习】Context详解

    Context概述 Context负责Activity,Service,Intent,资源,Package和权限:启动Activity启动和停止Service发送广播 消息注册广播消息接受者访问APK中各种资源访问Package的相关信息APK的各种权限管理Context继承关系Context个数 Context个数=Activity数+Service数+1(Applicat…...

    2024/4/20 3:05:30
  11. H5新增属性

    H5新增属 (1)manifest属性:定义页面需要用到的离线应用文件,一般放在标签里 (2)charset属性:meta属性之一,定义页面的字符集 (3)sizes属性: 新增属性,当link的rel="icon"时,用以设置图标大小 (4)base属性: 表示当在新窗口打开一个页面时,会将href中的…...

    2024/4/15 20:42:36
  12. 关于elementUI中,表格el-table在ie中宽度不为100%的问题

    可以在相应的页面中不添加任何前缀添加以下css,即可适应全局的表格 //关于ie下表格宽度不为100%的问题 .el-table__header{width: 100% !important; } .el-table__body{width: 100% !important; }...

    2024/4/15 20:42:35
  13. 4.forgot

    from pwn import * p=remote(220.249.52.133,49466) p.recvuntil("> ") p.sendline(A) payload=A*32+p32(0x080486cc) p.recvuntil("> ") p.sendline(payload)print p.recvall()...

    2024/4/15 20:42:39
  14. 网络通信与便携式应用驱动SRAM技术发展

    数据通信和便携式系统成为当今SRAM的重要应用领域。某些SRAM由于能够提供实现较高带宽所需的性能(比如在网络系统中)或维持较长电池使用寿命所需的低功耗(比如在便携式设备中)而在许多应用中起着主导作用。这些架构指的是面向高性能应用的NoBL (无总线延迟)和QDR (四倍数据速率…...

    2024/4/25 19:27:02
  15. jq子页面取值赋值给父页面数据

    //父窗口 <input type="text" name="no" id="no"/>//子窗口 <input type="radio" name="no" value="1"/> <input type="radio" name="no" value="2"/> <butt…...

    2024/4/25 6:23:16
  16. xshell6 要继续使用此程序,您必须应用最新的更新或使用新版本

    1、xshell文件目录中找到文件 nslicense.dll2、下载UltraEdit编辑工具,将nslicense.dll拖入此工具打开dll文件3、ctrl+f 搜索 7F 0C 81 F9 80 33 E1 01 0F 86 81 ,将86改为83,ctrl+s保存,xshell6已经可以正常打开,...

    2024/4/28 14:54:14
  17. Reactor 3 (9): 并发和调度器 Schedulers、publishOn、subscribeOn

    Stream中的并行处理非常简单,只要加上parallel(),就可以将stream并行化:@Testpublic void streamParallel () {Stream.of(1,2,3,4,5,6,7,8).parallel().map(String::valueOf).forEach(log::info);} }根据结果中线程使用情况可知这种操作就完成了stream的并行化:Reactor的并…...

    2024/4/29 10:52:34
  18. MyOS 之 基础图形库

    能够在240*320的屏幕上画出矩形,包括实心的,空心的,各种颜色,边框暂不考虑。...

    2024/4/28 18:12:12
  19. 细解SimpleDateFormat

    其实,作为一名Java 程序员,我们会经常在编程时候和时间打交道,比如要把某一个时间存储到数据库中去,而我们直接使用Datedate = newDate(); System.out.println(date);得到的时间都是这样的SunJun 07 17:22:52CST 2020因此,我们经常需要把时间进行格式化处理,然后在进行存…...

    2024/4/30 22:51:27
  20. kmp一道唬人题

    P - Period II 描述 For each prefix with length P of a given string S,if S[i]=S[i+P] for i in [0…SIZE(S)-p-1], then the prefix is a “period” of S. We want to all the periodic prefixs. Input Input contains multiple cases. The first line contains an intege…...

    2024/4/27 1:18:22

最新文章

  1. SpringBoot之自定义注解参数校验

    SpringBoot之自定义注解参数校验 为什么要自定义注解 我这里先引入一个例子&#xff0c;就比如我现在要写文章&#xff0c;文章也许写完正要发布&#xff0c;也可以是还没写完正要存草稿&#xff0c;前端往后端发送数据&#xff0c;如果前端的state不是草稿或者已发布状态&…...

    2024/5/1 3:25:18
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. Java-运算符

    运算符 Java语言支持如下运算符&#xff1a; 算术运算符&#xff1a;&#xff0c;-&#xff0c;*&#xff0c;/&#xff0c;%&#xff0c;&#xff0c;--复制运算符&#xff1a;关系运算符&#xff1a;>, <, >, <, , !instanceof逻辑运算符&#xff1a;&&…...

    2024/4/30 4:47:07
  4. STL--vector有哪些应用场景

    vector 在 C 中是一种非常灵活和强大的容器&#xff0c;适用于多种不同的应用场景。以下是一些常见的应用场景&#xff1a; 1 动态数据集合&#xff1a;当你不确定数据集的大小&#xff0c;或者数据集的大小会随时间变化时&#xff0c;vector 是理想的选择。例如&#xff0c;在…...

    2024/4/30 3:33:36
  5. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/4/30 9:36:27
  6. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/4/30 0:57:52
  7. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/4/29 18:43:42
  8. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/4/29 19:40:09
  9. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/4/30 23:32:22
  10. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/4/30 23:16:16
  11. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/4/30 0:57:50
  12. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/4/29 21:25:29
  13. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/4/30 0:57:49
  14. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/4/30 14:53:47
  15. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/4/30 22:14:26
  16. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/4/29 7:41:18
  17. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/4/30 22:57:18
  18. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/4/30 20:39:53
  19. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/4/30 0:57:46
  20. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/4/30 0:57:46
  21. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/4/29 3:42:58
  22. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/4/29 19:56:39
  23. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/4/29 8:41:59
  24. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/4/30 20:52:33
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; 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
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在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