Spring框架学习总结

一、概述:

简介:

Spring 框架是一个开源的 Java 平台,轻量级的,Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。
使用 Spring 框架的好处:
1.降低组件之间的耦合度,实现软件各层之间的解耦。
2.可以使容器提供众多服务如事务管理消息服务处理等等。当我们使用容器管理事务时,开发人员就不需要手工 控制事务,也不需要处理复杂的事务传播。
3.容器提供单例模式支持,开发人员不需要自己编写实现代码。
4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能。
5.容器提供众多的辅佐类,使这些类可以加快应用的开发.如jdbcTemplate HibernateTemplate。

Spring 体系结构

Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。

在这里插入图片描述
核心容器
核心容器由spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

  • spring-core模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
  • context模块建立在由core和 beans 模块的基础上建立起来的,它以一种类似于JNDI注册的方式访问对象。Context模块继承自Bean模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过Servelet容器)等功能。Context模块也支持Java EE的功能,比如EJB、JMX和远程调用等。ApplicationContext接口是Context模块的焦点。spring-context-support提供了对第三方库集成到Spring上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。
  • spring-expression模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等。

它们的完整依赖关系如下图所示:

在这里插入图片描述

数据访问/集成:
数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下: (注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service):

  • JDBC 模块提供了JDBC抽象层,它消除了冗长的JDBC编码和对数据库供应商特定错误代码的解析。
  • ORM 模块提供了对流行的对象关系映射API的集成,包括JPA、JDO和Hibernate等。通过此模块可以让这些ORM框架和spring的其它功能整合,比如前面提及的事务管理。
  • OXM 模块提供了对OXM实现的支持,比如JAXB、Castor、XML Beans、JiBX、XStream等。
  • JMS 模块包含生产(produce)和消费(consume)消息的功能。从Spring 4.1开始,集成了spring-messaging模块。
  • 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写beginTransaction()、commit()、rollback()等事务管理方法,声明式事务是通过注解或配置由spring自动处理,编程式事务粒度更细)。

Web
Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

  • Web 模块提供面向web的基本功能和面向web的应用上下文,比如多部分(multipart)文件上传功能、使用Servlet监听器初始化IoC容器等。它还包括HTTP客户端以及Spring远程调用中与web相关的部分。
  • Web-MVC 模块为web应用提供了模型视图控制(MVC)和REST Web服务的实现。Spring的MVC框架可以使领域模型代码和web表单完全地分离,且可以与Spring框架的其它所有功能进行集成。
  • Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
  • Web-Portlet 模块提供了用于Portlet环境的MVC实现,并反映了spring-webmvc模块的功能。

其他
还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

  • AOP 模块提供了面向方面的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。
  • Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
  • Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
  • Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
  • 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

二、Spring IoC 容器

2.1、什么是IoC?

  • 控制反转,把对象创建和对象之间的调用交给spring进行管理。
  • 目的:降低耦合度。
  • Ioc底层原理:xml解析,工厂模式,反射。
    在这里插入图片描述

2.2、Spring 的 BeanFactory 、ApplicationContext 容器:

ioc思想的实现:是基于IOC容器完成的,容器的底层就是对象工厂。

BeanFactory接口:
是ioc基本的实现,是 Spring 内部的使用接口,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象,不提供开发人员进行使用。
(1) spring的原始接口,针对原始接口的实现类功能较为单一
(2)BeanFactory接口实现类的容器,特点是每次在获得对象时才会创建对象

ApplicationContext接口
BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件对象进行创建。(也被称为Spring的上下文)
(1)每次容器启动时就会创建容器中配置的所有对象
(2)提供了更多功能
(3)从类路径下加载配置文件: ClassPathXmlApplicationContext
从硬盘的绝对路径下加载配置文件:FileSystemXmlApplication
在这里插入图片描述

2.3、Spring Bean 定义:

bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象,由用容器提供的配置元数据创建的。

bean 定义的下列属性:在这里插入图片描述

2.4、Spring Bean 作用域

当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为 singleton。
在这里插入图片描述
Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。

<bean id="..." class="..." scope="singleton">
    <!-- collaborators and configuration for this bean go here -->
</bean>

Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。

<bean id="..." class="..." scope="prototype">
   <!-- collaborators and configuration for this bean go here -->
</bean>

2.5、Spring Bean 生命周期

Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁

(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(4)bean 可以使用了(对象获取到了)
(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

<bean id=“orders” class=“com.atguigu.spring5.bean.Orders” initmethod=“initMethod” destroy-method=“destroyMethod”>

对比上面的:
添加bean的后置处理器,让生命周期有七步:
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
(6)bean 可以使用了(对象获取到了)
(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
演示添加后置处理器效果:

(1)创建类,实现接口 BeanPostProcessor,创建后置处理器
public class MyBeanPost implements BeanPostProcessor {
 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) 
throws BeansException {
 System.out.println("在初始化之前执行的方法");
 return bean;
 }
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) 
throws BeansException {
 System.out.println("在初始化之后执行的方法");
 return bean;
 } }

三、spring依赖注入

3.1、Spring 基于构造函数的依赖注入

如果存在不止一个参数时,当把参数传递给构造函数时,可能会存在歧义。要解决这个问题,那么构造函数的参数在 bean 定义中的顺序就是把这些参数提供给适当的构造函数的顺序就可以了。

<beans>
   <bean id="foo" class="x.y.Foo">
      <constructor-arg ref="bar"/>
      <constructor-arg ref="baz"/>
   </bean>

   <bean id="bar" class="x.y.Bar"/>
   <bean id="baz" class="x.y.Baz"/>
</beans>

如果你使用 type 属性显式的指定了构造函数参数的类型,容器也可以使用与简单类型匹配的类型。例如:

<beans>

   <bean id="exampleBean" class="examples.ExampleBean">
      <constructor-arg type="int" value="2001"/>
      <constructor-arg type="java.lang.String" value="Zara"/>
   </bean>

</beans>

最后并且也是最好的传递构造函数参数的方式,使用 index 属性来显式的指定构造函数参数的索引。下面是基于索引为 0 的例子,如下所示:

<beans>

   <bean id="exampleBean" class="examples.ExampleBean">
      <constructor-arg index="0" value="2001"/>
      <constructor-arg index="1" value="Zara"/>
   </bean>

</beans>

3.2、Spring 基于设值函数的依赖注入(set方法注入)

你应该注意定义在基于构造函数注入和基于设值函数注入中的 Beans.xml 文件的区别。唯一的区别就是在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素,而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素。
第二个你需要注意的点是,如果你要把一个引用传递给一个对象,那么你需要使用 标签的 ref 属性,而如果你要直接传递一个值,那么你应该使用 value 属性。

<?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-3.0.xsd">

   <bean id="john-classic" class="com.example.Person">
      <property name="name" value="John Doe"/>
      <property name="spouse" ref="jane"/>
   </bean>

   <bean name="jane" class="com.example.Person">
      <property name="name" value="John Doe"/>
   </bean>

</beans>

使用 p-namespace 实现 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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="john-classic" class="com.example.Person"
      p:name="John Doe"
      p:spouse-ref="jane"/>
   </bean>

   <bean name="jane" class="com.example.Person"
      p:name="John Doe"/>
   </bean>

</beans>

3.3、Spring 注入内部 Beans

实例:
比如一个部门对应多个员工


//部门类
public class Dept {
 private String dname;
 public void setDname(String dname) {
 this.dname = dname;
 } }

//员工类
public class Emp {
 private String ename;
 private String gender;
 //员工属于某一个部门,使用对象形式表示
 private Dept dept; //这个Spring 注入内部 Beans
 
 public void setDept(Dept dept) {
 this.dept = dept;
 }
 public void setEname(String ename) {
 this.ename = ename;
 }
 public void setGender(String gender) {
 this.gender = gender;
 }}

<bean id="emp" class="com.atguigu.spring5.bean.Emp">
 <!--设置两个普通属性-->
 <property name="ename" value="lucy"></property>
 <property name="gender" value="女"></property>

<!--级联赋值-->
 <property name="dept" ref="dept"></property>
</bean> 

<bean id="dept" class="com.atguigu.spring5.bean.Dept">
 <property name="dname" value="财务部"></property>
</bean>
 

3.4、Spring 的集合注入

所有类型的集合的配置文件 Beans.xml 文件:

<!-- Definition for javaCollection -->
   <bean id="javaCollection" class="com.tutorialspoint.JavaCollection">

      <!-- results in a setAddressList(java.util.List) call -->
      <property name="addressList">
         <list>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
         </list>
      </property>

      <!-- results in a setAddressSet(java.util.Set) call -->
      <property name="addressSet">
         <set>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
        </set>
      </property>

      <!-- results in a setAddressMap(java.util.Map) call -->
      <property name="addressMap">
         <map>
            <entry key="1" value="INDIA"/>
            <entry key="2" value="Pakistan"/>
            <entry key="3" value="USA"/>
            <entry key="4" value="USA"/>
         </map>
      </property>

      <!-- results in a setAddressProp(java.util.Properties) call -->
      <property name="addressProp">
         <props>
            <prop key="one">INDIA</prop>
            <prop key="two">Pakistan</prop>
            <prop key="three">USA</prop>
            <prop key="four">USA</prop>
         </props>
      </property>

   </bean>

下面的 Bean 定义将帮助你理解如何注入 bean 的引用作为集合的元素。甚至你可以将引用和值混合在一起,如下所示:

<!-- Bean Definition to handle references and values -->
   <bean id="..." class="...">

      <!-- Passing bean reference  for java.util.List -->
      <property name="addressList">
         <list>
            <ref bean="address1"/>
            <ref bean="address2"/>
            <value>Pakistan</value>
         </list>
      </property>

      <!-- Passing bean reference  for java.util.Set -->
      <property name="addressSet">
         <set>
            <ref bean="address1"/>
            <ref bean="address2"/>
            <value>Pakistan</value>
         </set>
      </property>

      <!-- Passing bean reference  for java.util.Map -->
      <property name="addressMap">
         <map>
            <entry key="one" value="INDIA"/>
            <entry key ="two" value-ref="address1"/>
            <entry key ="three" value-ref="address2"/>
         </map>
      </property>

   </bean>

注入 null 和空字符串的值:

四、Spring Beans 自动装配

4.1、Spring 自动装配 byNamebyType

在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。
在 XML 配置文件中 beans 的 autowire 属性设置为 byType。然后,如果它的 type 恰好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和连接它的属性。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

如:将类中的引用类型通过名称注入
java文件:
public class TextEditor {
private SpellChecker spellChecker;
private String name;
//…set/get 方法…
}

xml:
//1. 以前的写法
< bean id=“textEditor” class=“com.tutorialspoint.TextEditor”>
< property name=“spellChecker” ref=“spellChecker” />
< property name=“name” value=“Generic Text Editor” />
< /bean>
< bean id=“spellChecker” class=“com.tutorialspoint.SpellChecker”>< /bean>

//2. byName的写法
< bean id=“textEditor” class=“com.tutorialspoint.TextEditor”
autowire=“byName”>
< bean id=“spellChecker” class=“com.tutorialspoint.SpellChecker”></ bean>

// 3. bytype的写法
< bean id=“textEditor” class=“com.tutorialspoint.TextEditor”
autowire=“byType”>
< property name=“name” value=“Generic Text Editor” />
</ bean>

< bean id=“SpellChecker” class=“com.tutorialspoint.SpellChecker”>
< /bean>

4.2、Spring 由构造函数自动装配

Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。如果找到匹配项,它会注入这些 bean,否则,它会抛出异常。

//以前的写法
 <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <constructor-arg  ref="spellChecker" />
      <constructor-arg  value="Generic Text Editor"/>
   </bean>
     <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
   
//构造函数自动装配
<bean id="textEditor" class="com.tutorialspoint.TextEditor" 
      autowire="constructor">
      <constructor-arg value="Generic Text Editor"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="SpellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>

五、Spring 基于注解的配置

从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。在 XML 注入之前进行注解注入,因此后者的配置将通过两种方式的属性连线被前者重写。
我们将需要在我们的 Spring 配置文件中启用它:

<context:annotation-config/>

Spring 针对 Bean 管理中创建对象提供注解
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository

  • 上面四个注解功能是一样的,都可以用来创建 bean 实例
  1. @Required 注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML
    配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。

  2. @Autowired:根据属性类型进行自动装配

@Service
public class UserService {
 //定义 dao 类型属性
 //不需要添加 set 方法
 //添加注入属性注解
 @Autowired 
 private UserDao userDao;
 public void add() {
 System.out.println("service add.......");
 userDao.add();
 } }
  1. @Qualifier:根据名称进行注入

这个@Qualifier 注解的使用,和上面@Autowired 一起使用


//定义 dao 类型属性
//不需要添加 set 方法
//添加注入属性注解
@Autowired //根据类型进行注入
@Qualifier(value = "userDaoImpl1") //根据名称进行注入
private UserDao userDao; 
  1. @Resource:可以根据类型注入,可以根据名称注入

//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入
private UserDao userDao; 
  1. @Value:注入普通类型属性
@Value(value = "abc")
private String name; 
  1. Spring JSR-250 注释:
    @PostConstruct 和 @PreDestroy 注释:
    为了定义一个 bean 的安装和卸载,我们使用 init-method 和/或 destroy-method 参数简单的声明一下 。init-method 属性指定了一个方法,该方法在 bean 的实例化阶段会立即被调用。同样地,destroy-method 指定了一个方法,该方法只在一个 bean 从容器中删除之前被调用。

7.完全注解开发,基于 Java 的配置

(1)创建配置类,替代 xml 配置文件


@Configuration //作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
   @Bean
   @Scope("prototype")
   public Foo foo() {
      return new Foo();
   }
}

(2)编写测试类
@Test
public void testService2() {
//加载配置类
ApplicationContext context
= new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean(“userService”,
UserService.class);
System.out.println(userService);
userService.add();
}

六、Spring 框架的 AOP

Spring 框架的一个关键组件是面向方面的编程(AOP)框架。面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样的常见的很好的方面的例子,如日志记录、审计、声明式事务、安全性和缓存等。
AOP 术语
在我们开始使用 AOP 工作之前,让我们熟悉一下 AOP 概念和术语。这些术语并不特定于 Spring,而是与 AOP 有关的。在这里插入图片描述
通知的类型
Spring 方面可以使用下面提到的五种通知工作:
在这里插入图片描述

Aop底层原理:(动态代理)
(1)有两种情况动态代理
第一种,有接口情况,使用JDK动态代理
第二种,没有接口情况,使用CGLIB

Spring 框架的 AOP :
一般都是基于 AspectJ,AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使
用,进行 AOP 操作。

基于 AspectJ 实现 AOP 操作
(1)基于 xml 配置文件实现
(2)基于注解方式实现(使用)

6.1、Spring 中基于 AOP 的 XML架构

准备目标对象(被代理对象,被通知的对象,被增强的类对象)
在这里插入图片描述

  2、准备通知(被增强方法的代码,想要实现功能的方法代码)

在这里插入图片描述

3、配置 applicationContext.xml
1.导入aop(约束)命名空间
2.配置目标对象
3.配置通知对象
4.配置将通知织入目标对象

在这里插入图片描述

4、测试

在这里插入图片描述

总结:通知的几种类型
1.前置通知———目标方法运行之前调用
2.后置通知———目标方法运行之后调用(如果出现异常不调用)
3.环绕通知———目标方法之前和之后都调用
4.异常拦截通知———如果出现异常,就会调用
5.后置通知———目标方法运行之后调用(无论是否出现异常都会调用)

6.2、基于注解

切入点表达式:
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] 方法名称 )
举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.atguigu.dao.BookDao.add(…))
举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (…))
举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.. (…))

1、创建类

public class User {
 public void add() {
 System.out.println("add.......");
 } }

2、创建增强类(编写增强逻辑)
(1)在增强类里面,创建方法,让不同方法代表不同通知类型

//增强的类
public class UserProxy {
 public void before() {//前置通知
 System.out.println("before......");
 } }

3、进行通知的配置
使用注解创建 User 和 UserProxy 对象(前提开启注解扫描)

//被增强的类
@Component
public class  User{
....
}

//增强的类
@Component
@Aspect              //在增强类上面添加注解 @Aspect
public class UserProxy{
.....
}

在 spring 配置文件中开启生成代理对象

<!-- 开启 Aspect 生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 

4、配置不同类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置


//增强的类
@Component
@Aspect //生成代理对象
public class UserProxy {
 //前置通知
 //@Before 注解表示作为前置通知
 @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
 public void before() {
 System.out.println("before.........");
 }
 //后置通知(返回通知)
 @AfterReturning(value = "execution(* 
com.atguigu.spring5.aopanno.User.add(..))")
 public void afterReturning() {
 System.out.println("afterReturning.........");
 }
 //最终通知
 @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
 public void after() {
 System.out.println("after.........");
 }
 //异常通知
 @AfterThrowing(value = "execution(* 
com.atguigu.spring5.aopanno.User.add(..))")
 public void afterThrowing() {
 System.out.println("afterThrowing.........");
 }
 //环绕通知
 @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
 public void around(ProceedingJoinPoint proceedingJoinPoint) throws 
Throwable {
 System.out.println("环绕之前.........");
 //被增强的方法执行
 proceedingJoinPoint.proceed();
 System.out.println("环绕之后.........");
 } }

5、相同的切入点抽取
//相同切入点抽取
@Pointcut(value = “execution(* com.atguigu.spring5.aopanno.User.add(…))”)
public void pointdemo() {
}
//前置通知
//@Before 注解表示作为前置通知
@Before(value = “pointdemo()”)
public void before() {
System.out.println(“before…”);
}

6、有多个增强类多同一个方法进行增强,设置增强类优先级
(1)在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy

7、完全使用注解开发
(1)创建配置类,不需要创建 xml 配置文件
@Configuration
@ComponentScan(basePackages = {“com.atguigu”})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}

七、Spring JDBC 框架

7.1、配置数据源

(1)Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作
(2)在 spring 配置文件配置数据库连接池

destroy-method=“close”>
< property name=“url” value=“jdbc:mysql:///user_db” />
< property name=“username” value=“root” />
< property name=“password” value=“root” />
< property name=“driverClassName” value=“com.mysql.jdbc.Driver” />
</ bean>
(3)配置 JdbcTemplate 对象,注入 DataSource

< bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

< property name=“dataSource” ref=“dataSource”></ property>
</ bean>
(4)创建 service 类,创建 dao 类,在 dao 注入 jdbcTemplate 对象

  • 配置文件
< context:component-scan base-package="com.atguigu">

7.2、增删改查

7.2.1、JdbcTemplate 操作数据库(添加)

//1 创建 sql 语句
String sql = “insert into t_book values(?,?,?)”;
//2 调用方法实现
Object[] args = {book.getUserId(), book.getUsername(), book.getUstatus()};
int update = jdbcTemplate.update(sql,args);

7.2.2、JdbcTemplate 操作数据库(修改和删除):

修改
String sql = “update t_book set username=?,ustatus=? where user_id=?”;
Object[] args = {book.getUsername(), book.getUstatus(),book.getUserId()};
int update = jdbcTemplate.update(sql, args);

删除
String sql = “delete from t_book where user_id=?”;
int update = jdbcTemplate.update(sql, id);

7.2.3、使用 JdbcTemplate 实现查询返回某个值代码

String sql = “select count(*) from t_book”;
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);

7.2.4、JdbcTemplate 实现查询返回对象

String sql = “select * from t_book where user_id=?”;
//调用方法
Book book = jdbcTemplate.queryForObject(sql,
new BeanPropertyRowMapper(Book.class),
id);

7.2.5、调用 JdbcTemplate 方法实现查询返回集合

String sql = “select * from t_book”;
//调用方法
List bookList = jdbcTemplate.query(sql, new
BeanPropertyRowMapper(Book.class));

7.3、批量增删改

7.3.1、JdbcTemplate 实现批量添加操作

String sql = “insert into t_book values(?,?,?)”;
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);

7.3.2、JdbcTemplate 实现批量修改操作

String sql = “update t_book set username=?,ustatus=? where user_id=?”;
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);

7.3.3、JdbcTemplate 实现批量删除操作

String sql = “delete from t_book where user_id=?”;
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);

八、Spring 事务管理

在这里插入图片描述

事务的概念可以描述为具有以下四个关键属性说成是 ACID:
特性:

  • 原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。

  • 一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等。

  • 隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。

  • 持久性:一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

    Spring事物管理俩种方式:在 Spring 进行声明式事务管理,底层使用 AOP 原理
    1.编程式事物管理
    2.声明式事物管理

8.1、 声明式事物管理

(1)基于注解方式(使用)
(2)基于 xml 配置文件方式

Spring 事务管理 API
(1)提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

在这里插入图片描述

1、在 spring 配置文件配置事务管理器

class=“org.springframework.jdbc.datasource.DataSourceTransactionManager”>

< property name=“dataSource” ref=“dataSource”></ property>
</ bean>

2、在 spring 配置文件,开启事务注解
(1)在 spring 配置文件引入名称空间 tx
xmlns:tx=“http://www.springframework.org/schema/tx”

(2)开启事务注解

3、在 service 类上面(或者 service 类里面方法上面)添加事务注解
(1)@Transactional,这个注解添加到类上面,也可以添加方法上面
(2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务
(3)如果把这个注解添加方法上面,为这个方法添加事务
@Service
@Transactional
public class UserService {

在 service 类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数:
在这里插入图片描述
1、propagation:事务传播行为

(1)多事务方法直接进行调用,这个过程中事务 是如何进行管理的
在这里插入图片描述
示例:
在这里插入图片描述

2、ioslation:事务隔离级别

(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题
(2)有三个读问题:脏读、不可重复读、虚(幻)读
(3)脏读:一个未提交事务读取到另一个未提交事务的数据
(4)不可重复读:一个未提交事务读取到另一提交事务修改数据
(5)虚读:一个未提交事务读取到另一提交事务添加数据

在这里插入图片描述

在这里插入图片描述

(6)解决:通过设置事务隔离级别,解决读问题

在这里插入图片描述

3、timeout:超时时间

(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是 -1 ,设置时间以秒单位进行计算

4、readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作
(3)设置 readOnly 值是 true,设置成 true 之后,只能查询
5、rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
6、noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚

(完全注解声明式事务管理)


1、创建配置类,使用配置类替代 xml 配置文件
@Configuration //配置类
@ComponentScan(basePackages = "com.atguigu") //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
 //创建数据库连接池
 @Bean
 public DruidDataSource getDruidDataSource() {
 DruidDataSource dataSource = new DruidDataSource();
 dataSource.setDriverClassName("com.mysql.jdbc.Driver");
 dataSource.setUrl("jdbc:mysql:///user_db");
 dataSource.setUsername("root");
 dataSource.setPassword("root");
 return dataSource;
 }
 //创建 JdbcTemplate 对象
 @Bean
 public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
 //到 ioc 容器中根据类型找到 dataSource
 JdbcTemplate jdbcTemplate = new JdbcTemplate();
 //注入 dataSource
 jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
 }
 //创建事务管理器
 @Bean
 public DataSourceTransactionManager 
getDataSourceTransactionManager(DataSource dataSource) {
 DataSourceTransactionManager transactionManager = new 
DataSourceTransactionManager();
 transactionManager.setDataSource(dataSource);
 return transactionManager;
 } }

事务操作(XML 声明式事务管理)

1、在 spring 配置文件中进行配置
第一步 配置事务管理器
第二步 配置通知
第三步 配置切入点和切面

<!--1 创建事务管理器--> <bean id="transactionManager" 
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <!--注入数据源-->
 <property name="dataSource" ref="dataSource"></property>
</bean>
<!--2 配置通知--> <tx:advice id="txadvice">
 <!--配置事务参数-->
 <tx:attributes>
 <!--指定哪种规则的方法上面添加事务-->
 <tx:method name="accountMoney" propagation="REQUIRED"/>
 <!--<tx:method name="account*"/>-->
 </tx:attributes>
</tx:advice>
<!--3 配置切入点和切面--> <aop:config>
 <!--配置切入点-->
 <aop:pointcut id="pt" expression="execution(* 
com.atguigu.spring5.service.UserService.*(..))"/>
 <!--配置切面-->
 <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>

九、Spring5 框架新功能
1、整个 Spring5 框架的代码基于 Java8,运行时兼容 JDK9,许多不建议使用的类和方
法在代码库中删除。

2、Spring 5.0 框架自带了通用的日志封装 (1)Spring5 已经移除 Log4jConfigListener,官方建议使用 Log4j2
(2)Spring5 框架整合 Log4j2

3、Spring5 框架核心容器支持@Nullable 注解
(1)@Nullable 注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以
为空,参数值可以为空
(2)注解用在方法上面,方法返回值可以为空
在这里插入图片描述

(3)注解使用在方法参数里面,方法参数可以为空
在这里插入图片描述

(4)注解使用在属性上面,属性值可以为空
在这里插入图片描述

4、Spring5 核心容器支持函数式风格 GenericApplicationContext

//函数式风格创建对象,交给 spring 进行管理
@Test
public void testGenericApplicationContext() {
//1 创建 GenericApplicationContext 对象
GenericApplicationContext context = new GenericApplicationContext();
//2 调用 context 的方法对象注册
context.refresh();
context.registerBean(“user1”,User.class,() -> new User());
//3 获取在 spring 注册的对象
// User user = (User)context.getBean(“com.atguigu.spring5.test.User”);
User user = (User)context.getBean(“user1”);
System.out.println(user);
}

5、Spring5 支持整合 JUnit5

(1)整合 JUnit4
第一步 引入 Spring 相关针对测试依赖
在这里插入图片描述

第二步 创建测试类,使用注解方式完成
@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration(“classpath:bean1.xml”) //加载配置文件

public class JTest4 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
} }

(2)Spring5 整合 JUnit5
第一步 引入 JUnit5 的 jar 包
在这里插入图片描述

第二步 创建测试类,使用注解完成
@ExtendWith(SpringExtension.class)
@ContextConfiguration(“classpath:bean1.xml”)
public class JTest5 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
} }

(3)使用一个复合注解替代上面两个注解完成整合
@SpringJUnitConfig(locations = “classpath:bean1.xml”)
public class JTest5 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
} }

九、Spring5 框架新功能

1、整个 Spring5 框架的代码基于 Java8,运行时兼容 JDK9,许多不建议使用的类和方
法在代码库中删除
2、Spring 5.0 框架自带了通用的日志封装 (1)Spring5 已经移除 Log4jConfigListener,官方建议使用 Log4j2
(2)Spring5 框架整合 Log4j2
第一步 引入 jar 包
在这里插入图片描述

第二步 创建 log4j2.xml 配置文件


<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > 
ALL -->
<!--Configuration 后面的 status 用于设置 log4j2 自身内部的信息输出,可以不设置,
当设置成 trace 时,可以看到 log4j2 内部各种详细输出--> <configuration status="INFO">
 <!--先定义所有的 appender-->
 <appenders>
 <!--输出日志信息到控制台-->
 <console name="Console" target="SYSTEM_OUT">
 <!--控制日志输出的格式-->
 <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-
5level %logger{36} - %msg%n"/>
 </console>
 </appenders>
 <!--然后定义 logger,只有定义 logger 并引入的 appender,appender 才会生效-->
 <!--root:用于指定项目的根日志,如果没有单独指定 Logger,则会使用 root 作为
默认的日志输出-->
 <loggers>
 <root level="info">
 <appender-ref ref="Console"/>
 </root>
 </loggers>
</configuration> 

3、Spring5 框架核心容器支持@Nullable 注解
(1)@Nullable 注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以
为空,参数值可以为空
(2)注解用在方法上面,方法返回值可以为空
在这里插入图片描述

(3)注解使用在方法参数里面,方法参数可以为空
在这里插入图片描述

(4)注解使用在属性上面,属性值可以为空
在这里插入图片描述

4、Spring5 核心容器支持函数式风格 GenericApplicationContext


//函数式风格创建对象,交给 spring 进行管理
@Test
public void testGenericApplicationContext() {
 //1 创建 GenericApplicationContext 对象
 GenericApplicationContext context = new GenericApplicationContext();
 //2 调用 context 的方法对象注册
 context.refresh();
 context.registerBean("user1",User.class,() -> new User());
 //3 获取在 spring 注册的对象
 // User user = (User)context.getBean("com.atguigu.spring5.test.User");
 User user = (User)context.getBean("user1");
 System.out.println(user);
}

5、Spring5 支持整合 JUnit5
(1)整合 JUnit4
第一步 引入 Spring 相关针对测试依赖
在这里插入图片描述

第二步 创建测试类,使用注解方式完成


@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:bean1.xml") //加载配置文件
public class JTest4 {
 @Autowired
 private UserService userService;
 @Test
 public void test1() {
 userService.accountMoney();
 } }

(2)Spring5 整合 JUnit5
第一步 引入 JUnit5 的 jar 包
在这里插入图片描述

第二步 创建测试类,使用注解完成

@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean1.xml")
public class JTest5 {
 @Autowired
 private UserService userService;
 @Test
 public void test1() {
 userService.accountMoney();
 } }

(3)使用一个复合注解替代上面两个注解完成整合

@SpringJUnitConfig(locations = "classpath:bean1.xml")
public class JTest5 {
 @Autowired
 private UserService userService;
 @Test
 public void test1() {
 userService.accountMoney();
 } }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值