Spring总结

Spring总结

Spring的概述

①Spring是一个开源框架

②Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。

③Spring是一个IOC(DI)和AOP容器框架。

④Spring的优良特性

[1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API

[2]控制反转:IOC——Inversion of Control,指的是将对象的创建权交给Spring去创建。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。

[3]依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用setXX方法去设置,而是通过配置赋值。

[4]面向切面编程:Aspect Oriented Programming——AOP

[5]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期

​ [6]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。

​ [7]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。

自我理解,spring的三大内容:

1.ioc控制反转,依赖注入,通过配置xml信息或者设置注解生产bean对象,dao对象,service对象.

2.aop,面向切面,通过底层实现2个动态代理(java.lang.reflect动态代理,cjlib代理),实现面向方法编程,可以增强方法实现日志及其他功能,提高代码的复用性.

3.声明事事务:通过注解Transactional对方法进行注解,使其方法具有事务性,通过多种属性对不同的事务进行操作.

1. IOC控制反转 和 依赖注入

1.1 IOC 全称指的是 Inverse Of Control 控制反转。

使用Spring之前,我们对Bean对象的管制,都是自己手动的去new Xxx()。

而使用了Spring模型之后,我们把new的操作。交给Spring容器。

1.2 什么是DI

DI 指的是Dependency Injection 。是依赖注入的意思。原来在使用Spring之前。

Class BookService{

private BookDao bookDao ;

public void setBookDao( BookDao bookDao ){

this.bookDao = bookDao

}

Public BookService(){

​ bookDAO = new BookDAOImpl();

}

}

使用了Spring之后。我们只需要使用xml配置,或者注解配置。就可以直接注入。

1.3 搭建spring工程运行环境
1.核心jar包

4个及其日志打
印包2个–>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lk775SJY-1574917689982)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps1.jpg)]

**2、**创建log4j.properties日记配置文件

# Global logging configuration

log4j.rootLogger=INFO, stdout

# Console output…

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

**3、**创建Spring的配置文件

创建一个spring Bean config文件,sts软件自带

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKsDMgMN-1574917689983)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps2.jpg)]

4、创建一个JavaBean对象

public class Person {

private int id;

private String name;

private String phone;

private int age;

**5、**到Spring配置文件中配置你的Bean对象

​ <!-- bean标签用于配置一个组件对象(javaBean,Dao。Service)

​ id 是给bean对象起一个唯一的标识

​ class bean对象的具体全类名

​ -->

​ <bean id=“p1” class=“com.atguigu.pojo.Person”>

​ <!-- property标签用来配置属性信息

​ name 是属性名

​ value 是属性值–>

​ <property name=“id” value=“1”/>

​ <property name=“name” value=“华仔”/>

​ <property name=“age” value=“18”/>

​ <property name=“phone” value=“18699998888”/>

1.4 从spring容器获取bean对象的多种方式
1.4.1通过id获取对象(重点)

// 创建一个Spring容器对象

​ ApplicationContext applicationContext = new ClassPathXmlApplicationContext(

​ “application.xml”);

​ // getBean从Spring容器中获取指定的id值的 bean对象返回

​ Person person = (Person) applicationContext.getBean(“p1”);

常见错误说明:如果调用getBean多次,会创建几个?

答:默认创建同一个

1.4.2 IOC通过类型获取对象(重点)

​ Person person = applicationContext.getBean(Person.class);

当在applicationContext.xml配置文件中。

有多个同Person.class类型实现的时候。

按照Class类型查找的时候,如果没有,也会报错误.

1.4.3 IOC 通过构造方法参数名注入

<bean id=“p3” class=“com.atguigu.pojo.Person”>

​ <constructor-arg name=“id” value=“3” />

1.4.4 IOC index属性指定参数的位置

​ <bean id=“p4” class=“com.atguigu.pojo.Person”>

​ <!–

​ constructor-arg 表示使用构造方法注入属性值

​ name 表示构造方法的参数名

​ index 表示构造方法的参数顺序从0开始

​ value 表示要传入的构造方法的参数值

​ -->

​ <constructor-arg value=“4” index=“0”/>

1.4.5 IOC根据参数类型注入

​ <bean id=“p5” class=“com.atguigu.pojo.Person”>

​ <constructor-arg value=“5” index=“0” type=“int”/>

​ <constructor-arg value=“phone” index=“1” type=“java.lang.String”/>

​ <constructor-arg value=“10” index=“2” type=“java.lang.String”/>

注意当有多种同参数类型时,必须标注其在类中的索引,预防串值

1.4.6 IOC之 P名称空间

先通过namespaces设置P属性标签

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fqaAZEtK-1574917689984)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps3.jpg)]

xml中的配置:

​ <bean id=“p6” class=“com.atguigu.pojo.Person” p:id=“60” p:name=“第六个” p:phone=“6电话” p:age=“66”/>

1.4.7 IOC之子对象的赋值测试(重点)

创建一个带有其他类为属性的类

public class Person {

private int id;

private String name;

private String phone;

private int age;

private Car car;

public class Car {

private int id;

private String name;

在xml中的配置如下:

​ <bean id=“car1” class=“com.atguigu.pojo.Car”>

​ <property name=“id” value=“1”/>

​ <property name=“name” value=“宝马”/>

<bean id=“p7” class=“com.atguigu.pojo.Person”>

​ <property name=“id” value=“7”/>

​ <property name=“car” ref=“car1” />

使用ref可以引用其他对象

1.4.8 IOC之内部Bean的使用

<bean id=“p8” class=“com.atguigu.pojo.Person”>

​ <property name=“id” value=“8”/>

​ <property name=“car”>

​ <bean id=“innerCar” class=“com.atguigu.pojo.Car” p:id=“22” p:name=“内部汽车”>

常见错误:内部的Bean不能被外部使用

1.4.9 IOC之List属性的赋值

public class Person {

private int id;

private List list;

xml中的配置:

​ <bean id=“p9” class=“com.atguigu.pojo.Person”>

<property name=“id” value=“8”/>

<property name=“list”>

​ list1

​ list2

​ list3

1.4.10 IOC之Map属性的赋值

public class Person {

private int id;

private Map<String, Object>map;

Xml中的配置

<bean id=“p10” class=“com.atguigu.pojo.Person”>

​ <property name=“name” value=“这是第10个实验” />

​ <property name=“map”>

​ <entry key=“key1” value=“value1” />

​ <entry key=“key2” value=“value2” />

​ <entry key=“key3” value=“value3” />

1.4.11 IOC之Properties属性的赋值

public class Person {

private int id;

private Properties prop;

xml中的配置如下:

​ <bean id=“p11” class=“com.atguigu.pojo.Person”>

​ <property name=“name” value=“这是第10个实验” />

​ <property name=“prop”>

​ <prop key=“jdbc.url”>jdbc:mysql://localhost:3306/test

​ <prop key=“jdbc.password”>root

1.4.12 IOC之util 名称空间

util名称空间,可以定义通过util名称空间创建集合类型的bean

先在namespaces去命名一个util名称空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3XHQVc3R-1574917689984)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps4.jpg)]

在xml中的配置:

​ <util:list id=“list1”>

​ list1

​ list2

​ list3

​ </util:list>

​ <bean id=“p12” class=“com.atguigu.pojo.Person”>

​ <property name=“name” value=“这是12个Person” />

​ <property name=“list” ref=“list1” />

1.4.13 IOC之级联属性赋值

在xml中的配置:

​ <bean id=“p13” class=“com.atguigu.pojo.Person”>

​ <property name=“name” value=“这是12个Person” />

​ <property name=“car” ref=“car1”>

​ <property name=“car.id” value=“2” />

​ <property name=“car.name” value=“级联属性赋值” />

常见错误:级联属性一定要先注入对象。再注入对象的属性

1.4.14 IOC之静态工厂方法创建Bean

1、创建一个工厂类

public class PersonFactory {

public static Person createPerson() {

​ Person person = new Person();

​ person.setName(“这是通过静态工厂方法创建的Person对象”);

return person;

​ }

2、到xml中去配置:

​ id 还是bean的唯一标识

​ class 属性定义工厂类全类名

​ factory-method 属性是调用哪个方法,的方法名

​ <bean id=“p14” class=“com.atguigu.util.PersonFactory” factory-method=“createPerson” />

1.4.15 IOC之工厂实例方法创建Bean

public Person createPerson2() {

​ Person person = new Person();

​ person.setName(“这是通过工厂实例对象创建的Person”);

return person;

​ }

Xml配置如下 先创建一个有实例方法的对象,通过对象调用方法获得返回对象

<bean id=“personFactory” class=“com.atguigu.util.PersonFactory” />

​ <!–

​ id是唯一的标识

​ factory-bean 引用哪个工厂对象的实例

​ factory-method 同时是调用哪个方法,的方法名

​ -->

<bean id=“p15” factory-bean=“personFactory” factory-method=“createPerson2” />

1.4.16 IOC之FactoryBean接口方式创建对象

实现FactoryBean接口的类

Public class PersonFactoryBean implements FactoryBean {

实现他的方法

返回创建的对象

​ @Override

public Person getObject() throws Exception {

​ Person person = new Person();

​ person.setName(“这是FactoryBean接口的方式创建的”);

return person;

​ * 返回创建的对象的类型

​ @Override

public Class<?> getObjectType() {

return Person.class;

​ * 是否是单例

​ @Override

public boolean isSingleton() {

return true;

在xml配置文件中的配置:

​ <bean id=“p16” class=“com.atguigu.util.PersonFactoryBean” />

1.4.17 IOC之继承Bean配置

通过继承实现bean配置信息的重用

<bean id=“p1” class=“com.atguigu.pojo.Person”>

<bean id=“p17” class=“com.atguigu.pojo.Person” parent=“p1”>

1.4.18 IOC之abstract抽象Bean

<bean id=“p1” class=“com.atguigu.pojo.Person” abstract=“true”>

如果配置的bean标签对象,设置了属性abstract=*“true”**,*那么此标签中的对象不能实例化

1.4.19 IOC之组件创建顺序

bean之间的依赖 depends-on 属性

depends-on=“b” 如果要创建a对象,就要有b对象也就是要先创建b再创建a

​ <bean id=“a” class=“com.atguigu.pojo.A” depends-on=“b”>

​ <bean id=“b” class=“com.atguigu.pojo.B”>

​ <bean id=“c” class=“com.atguigu.pojo.C”>

1.4.20 IOC之Bean的单例和多例(重点)

测试bean的作用域,分别创建单实例和多实例的bean★

scope 属性设置范围

		singleton		默认情况	是singleton,表示Spring容器中只有一个单例

						单例是在Spring容器创建的时候。初始化所有单例Bean对象

						并且每次调用Bean对象的时候,原来原来Spring容器中的对象

						

		prototype				prototype是表示当前配置的Bean对象是多例。

								在Spring容器被创建的时候,bean不会被创建出来。

								并且每次调用getBean方法都会创建一个对象实例

				

		request				表示一次请求内,不管调用几次getBean方法,返回的都是同一个bean对象

							Object bean = request.getAttribute(xxx);

							if (bean == null) {

								bean = 创建一个

								request.setAttribute(xxx,bean);

							}

		session				表示一个Session对象内,不管调用几次getBean方法,返回的都同一个Bean对象

							Object bean = session.getAttribute(xxx);

							if (bean == null) {

								bean = 创建一个

								session.setAttribute(xxx,bean);

							}

 -->

​ <bean id=“p21” class=“com.atguigu.pojo.Person” scope=“prototype”>

1.4.21 基于xml配置文件的自动注入

​ autowire 设置自动装配的方式

​ default 和 no 一样,都表示不装配, 如果对象不你手动设置,就没有值。 byName 表示Spring容器会自动按照子对象的属性名,当成是id来查找对象。找到就注入,找不到就为null

​ 举例:private Car car;

​ 就会以car做为id去spring容器中去查找对象。找到就把值注入给属性car。

​ byType 表示Spring容器会自动的按照子对象的类型去查找bean对象注入。

​ 举例:private Car car;

​ Spring容器就会自动的按照Car.class类型去Spring容器中查找。

​ 如果说,找到一个,就注入

​ 如果没有找到,值就为null

​ 如果说,找到多个,就报错。

​ constructor 表示Spring容器会按照子对象的类型去查找构造方法,中参数需要的类型去注入。先按照类型查询,如果找到一个就注入。如果找到多个,再按照构造方法中参数的变量名做为id来查找,如果找到就注入。如果没有找到,就为null如果没有找到,值也为null

Xml中的配置

<bean id=“p22” class=“com.atguigu.pojo.Person” autowire=“constructor”>

1.5 BeanFactory和ApplicationContext的关系

BeanFactory

BeanFactory是Spring容器的基础接口,提供了基础的容器访问能力。

BeanFactory提供懒加载方式,只有通过getBean方法调用获取Bean才会进行实例化。

ApplicationContext继承自BeanFactory接口,ApplicationContext包含了BeanFactory中所有的功能。

具有自己独特的特性:

Bean instantiation/wiriting

Bean实例化/串联

自动BeanPostProcessor注册

自动BeanFactoryPostProcessor注册

方便的MessageSource访问

ApplicationEvent发布

ApplicationContext采用的是预加载,每个Bean都在ApplicationContext启动后实例化。

1.6对象的生命周期

IOC之Bean的生命周期 创建带有生命周期方法的bean

给A类添加生命周期方法:

public class A {

public A() {

​ System.out.println(“这是A对象被创建了”);

​ }

public void initA() {

​ System.out.println(“这里是初始化A的方法”);

​ }

public void destroyA() {

​ System.out.println(“这里是销毁A的方法”);

​ }

}

在xml配置文件中配置如下:

​ <!–

​ init-method=“initA” 设置初始化方法

​ destroy-method=“destroyA” 设置销毁的方法

​ -->

​ <bean id=“a” class=“com.atguigu.pojo.A” init-method=“initA” destroy-method=“destroyA”>

2. Spring管理数据库连接池(重点)

2.1 搭建spring环境导入数据库jar包

需要导入数据库驱动包以及数据库连接池

mysql-connector-java-5.1.37-bin.jar

druid-1.1.10.jar

2.2 Spring配置管理数据库连接池对象(重点)

在Spring的配置文件中配置数据库连接池对象

<bean id="dataSource"class=com.alibaba.druid.pool.DruidDataSource>

<property name=url value=jdbc:mysql://localhost:3306/atguigu />

<property name=“username value=“root” />

<property name=“password” value=“root” />

<property name=driverClassName value=“com.mysql.jdbc.Driver” />

2.3 使用context名称空间加载jdbc.properties配置文件(重点)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zAyKtoOM-1574917689984)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps5.jpg)]

​ <context:property-placeholder location=“classpath:jdbc.properties”/>

2.4 Spring引入单独的jdbc.properties配置文件(重点)

1、抽取四个jdbc连接属性到jdbc.properties属性配置文件中

jdbc.username=root

jdbc.password=root

jdbc.url=jdbc:mysql://localhost:3306/atguigu

jdbc.driverClassName=com.mysql.jdbc.Driver

2、使用PropertyPlaceholderConfigurer 来加载jdbc.properties属性配置文件

​ <bean class=“org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”>

​ <property name=“location” value=“classpath:jdbc.properties” />

3、使用加载后的jdbc.properties属性配置文件中的连接属性。

​ <bean id=“dataSource” class=com.alibaba.druid.pool.DruidDataSource>

​ <property name="*url " value="${jdbc.url}"* />

​ <property name=“username value="${jdbc.user}" />

​ <property name=“password” value="${jdbc.password}" />

​ <property name=“driverClassName value="${jdbc.driverClass}" />

3 Sring EL表达式(*了解内容*)

[SpEL测试I]在SpEL中使用字面量:使用格式:#{数值} #{“字符串” || ‘字符串’}

[SpEL测试II]在SpEL中引用其他bean使用格式:#{bean的id}

[SpEL测试III]在SpEL中引用其他bean的某个属性值使用格式: #{bean.属性名}

[SpEL测试IV]在SpEL中调用非静态方法使用格式: #{bean.方法名(参数)}

[SpEL测试V]在SpEL中调用静态方法使用格式:#{T(全名类).方法名(参数)}

[SpEL测试VI]在SpEL中使用运算符使用格式:#{表达式}

​ <bean id=“car” class=“com.atguigu.pojo.Car”>

​ <property name=“name” value=“宝马” />

​ <property name=“carNo” value=“京B123421” />

​ <bean id=“personEL” class=“com.atguigu.pojo.Person”>

-->

​ <property name=“car” value="#{car}"/>

​ <property name=“phone” value="#{car.name}" />

​ -->

​ <property name=“name” value="#{T(com.atguigu.pojo.Car).staticFun()}"

​ <property name=“salary” value="#{10*1024}"/>

4 Spring注解功能***(极其重要)

4.1注解配置Dao、Service、Controller组件

当我们使用Spring的注解功能的时候。需要把aop的jar包导入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xkvSI29H-1574917689985)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps6.jpg)]

通过注解分别创建Dao、Service、Controller★

Spring配置bean的常用注解有

@Controller 专门标注给web层的组件

@Service 专门给Service层的组件注解

@Repository 给Dao层组件标注

@Component 给Dao、Service、控制器Web层之外的组件进行标注。

@Scope 可以修改bean的Scope属性,默认不标注此注解表示单例.也可以通过注解修改为多例@Scope(value=“prototype”)

注解在类上的使用:

/**

* @Repository注解的功能相当于在Spring配置文件中做了如下的配置

*

*/

@Scope(value=“prototype”)

@Repository(value=“bookDao”)

public class BookDao {

当我们在类上使用了注解之后。一定要在Spring配置文件中加上包扫描的配置才能生效

context:component-scan 表示包扫描base-package 指定要扫描哪些包下的类(包含子包)

<context:component-scanbase-package=“com.atguigu” />

4.2指定扫描包时的过滤内容(*重要*)

使用context:include-filter指定扫描包时要包含的类–使用context:exclude-filter指定扫描包时不包含的类

<context:include-filter /> 设置包含的内容

**注意:**通常需要与use-default-filters属性配合使用才能够达到“仅包含某些组件”这样的效果。即:通过将use-default-filters属性设置为false,

<context:exclude-filter /> 设置排除的内容

类别示例说明
annotationcom.atguigu.XxxAnnotation过滤所有标注了XxxAnnotation的类。这个规则根据目标组件是否标注了指定类型的注解进行过滤
assignablecom.atguigu.BaseXxx过滤所有BaseXxx类的子类。这个规则根据目标组件是否是指定类型的子类的方式进行过滤。
aspectjcom.atguigu.*Service+所有类名是以Service结束的,或这样的类的子类。这个规则根据AspectJ表达式进行过滤。
regexcom.atguigu.anno.*所有com.atguigu.anno包下的类。这个规则根据正则表达式匹配到的类名进行过滤。
customcom.atguigu.XxxTypeFilter使用XxxTypeFilter类通过编码的方式自定义过滤规则。该类必须实现org.springframework.core.type.filter.TypeFilter接口

applicationContext.xml 中配置的内容如下

<!-- use-default-filters="false" 设置取消默认包含规则 -->

​ <context:component-scan base-package=“com.atguigu” use-default-filters=“false”>

​ <context:include-filter type=“annotation” expression=“org.springframework.stereotype.Service”/>

​ <context:exclude-filter type=“assignable” expression=“com.atguigu.service.BookService”/>

​ </context:component-scan>

以上配置会包含所有@Service注解的类。排除com.atguigu.service.BookService

4.3使用注解@Autowired自动装配

使用@Autowired注解实现根据类型实现自动装配★@Autowired 注解 会自动的根据标注的对象类型在Spring容器中查找相对应的类。如果找到,就自动装配。使用@Autowired注解,不需要get/set方法

@Repository

public class BookDao {

public BookDao() {

​ System.out.println(“BookDao也被初始化了”);

@Service(“bookService”)

public class BookService {

public BookService() {

​ System.out.println(“bookService被初始化了”);

​ * 实验35:使用@Autowired注解实现根据类型实现自动装配★

​ * 1、Spring容器会自动的根据对象的类型到Spring容器中去查找,然后注入值。

​ * 1、如果找到一个,就直接注入值

​ @Autowired

private BookDao bookDao;

​ @Override

public String toString() {

return “BookService [bookDao=” + bookDao + “]”;

多个同类型的bean如何自动装配如果资源类型的bean不止一个,默认根据@Autowired注解标记的成员变量名作为id查找bean,进行装配★

4.4使用**@Qualifier装配指定id的bean对象**

如果根据成员变量名作为id还是找不到bean,可以使用@Qualifier注解明确指定目标bean的id

@Repository(value=“aaa”)

public class BookDao {

public BookDao() {

​ System.out.println(“BookDao也被初始化了”);

@Repository(value=“bbb”)

public class BookDaoExt extends BookDao{

public BookDaoExt() {

​ System.out.println(“BookDaoExt也被初始化了”);

​ * @Qualifier 这个注解,可以给你标注的组件。按照给定的id去spring容器中查找,然后注入。

​ * 这个注解会改变默认规则,默认是按照变量名,做为id来查找。但是,当使用了。这个注解之后。就会按照给定的id来查找。

​ * 如果找到指定id的bean对象,就注入。如果找不到就报错

​ @Qualifier(“bbb”)

private BookDao bookDao;

@Autowired和@Qualifier在方法上的使用。

在方法的形参位置使用@Qualifier注解

private BookDao bookDaoExt;

​ * @Autowired 注解标注的方法和组件都是初始化的时候,就已经调用和注入了。

​ @Autowired

public void abc(@Qualifier(value = “aaa”) BookDao bookDao) {

​ System.out.println(“这是被标注了@Autowired注解的方法…………”);

​ System.out.println(bookDao);

this.bookDaoExt = bookDao;

4.5 @Autowired注解的required属性作用(因为会抑制报错,一般不推荐)

@Autowired注解中有一个属性,叫required是必须,必要的意思,默认值是true,

​ 表示被标注的bean对象。必须要有值注入。如果找不到注入。就报错。

​ 如果找不到,不希望它报错。就把此值改为false。则此对象的值可以为null。

​ @Autowired(required=false)

​ * @Qualifier 这个注解,可以给你标注的组件。按照给定的id去spring容器中查找,然后注入。

​ * 这个注解会改变默认规则,默认是按照变量名,做为id来查找。但是,当使用了。这个注解之后。就会按照给定的id来查找。

​ * 如果找到指定id的bean对象,就注入。如果找不到就报错

5泛型注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KyNssneJ-1574917689985)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps7.jpg)]

6 Spring的专有测试

先导入spring-test-4.0.0.RELEASE.jar包

@ContextConfiguration(locations = “classpath:application.xml”)

@RunWith(SpringJUnit4ClassRunner.class)

public class SpringJunit {

@Autowired

private BookService bookService;

​ @Autowired

private UserService userService;

​ @Autowired

private UserDao userDao;

​ @Test

public void test1() {

}

在测试类上加上注解@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = “classpath:application.xml”)

这样测试,就不用再获取spring对象了,且不用再使用getBean,使用@Autowired就可以直接装配对象了

7、AOP切面编程***(极其重要)

7.1 AOP是面向切面编程**(面向方法)**

全称:Aspect Oriented Programming

面向切面编程指的是:程序是运行期间,动态地将某段代码插入到原来方法代码的某些位置中。这就叫面向切面编程。

7.2 Aop编程的底层实现(使用代理)
7.2.1 jdk动态代理

Java.lang.reflect.Proxy 创建对象 new Proxy(参数1(被代理对象的类加载器),参数2(被代理对象的父接口),参数3 自定义的Invoctionhandler的核心处理器) 生产代理对象

Invoctionhandler处理器需要传入需要被代理的对象,重写invoke方法

​ @Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if (method.getDeclaringClass().equals(Object.class)) {

return method.invoke(target, args);

​ }

​ LogUtil.log(method.getName(), (int) args[0], (int) args[1]);

​ Object result = null;

try {

​ result = method.invoke(target, args);

​ System.out.println(“后置日记”);

​ } catch (Exception e) {

​ System.out.println(“异常日记”);

​ } finally {

​ System.out.println(“finally日记”);

​ }

return result;

优点:这种方式已经解决我们前面所有代理方法加强需要的问题。非常的灵活。而且可以方便的在后期进行维护和升级。

缺点:当然使用jdk动态代理,需要有接口。如果没有接口。就无法使用jdk动态代理。

7.2.2 cglib****代理

导入jar包cglib

public class CGLibProxyFactory implements MethodInterceptor {

public static Object getCGLibProxy(Object target, Callback callback) {

​ // 创建一个CGLig生成器

​ Enhancer enhancer = new Enhancer();

​ // 设置父类。因为cglib是通过类,进行代码,不是通过接口

​ enhancer.setSuperclass(target.getClass());

​ // 设置拦截的代理方法

​ enhancer.setCallback(callback);

​ // create 方法创建一个代理对象并返回

return enhancer.create();

​ @Override

public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy)

throws Throwable {

​ LogUtil.log(method.getName(), (int) params[0], (int) params[1]);

​ // 调用实际的对象的方法

​ // 一定要使用methodProxy对象

​ // 第一个参数是proxy代码对象的父类方法

​ Object result = methodProxy.invokeSuper(proxy, params);

​ System.out.println(“这是后置代码”);

return result;

​ }

优点:在没有接口的情况下,同样可以实现代理的效果。

缺点:同样需要自己编码实现代理全部过程。

但是为了更好的整合Spring框架使用。所以我们需要学习一下Spring 的AOP 功能。也就是学习Spring提供的AOP功能。

7.3AOP编程的专业术语
通知(Advice)

通知就是增强的代码。比如前置增强的代码。后置增强的代码。异常增强代码。返回结果通知代码。这些就叫通知

切面(Aspect)

切面就是包含有通知代码的类叫切面。

横切关注点

横切关注点,就是我们可以添加增强代码的位置。比如前置位置,后置位置,异常位置。和返回值位置。这些都叫横切关注点。

目标(Target)

目标对象就是被关注的对象。或者被代理的对象。

代理(Proxy)

为了拦截目标对象方法,而被创建出来的那个对象,就叫做代理对象。

连接点(Joinpoint)

连接点指的是横切关注点和程序代码的连接,叫连接点。

切入点(pointcut)

切入点指的是用户真正处理的连接点,叫切入点。

在Spring中切入点通过org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

7.4****图解AOP专业术语:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dLmbRgTs-1574917689985)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps8.jpg)]

7.5使用Spring实现AOP切面编程环境

需要导入工程的jar包

Spring的核心包

spring-beans-4.0.0.RELEASE.jar

spring-context-4.0.0.RELEASE.jar

spring-core-4.0.0.RELEASE.jar

spring-expression-4.0.0.RELEASE.jar

Spring的测试包

spring-test-4.0.0.RELEASE.jar

Spring日记相关包

commons-logging-1.1.3.jar

log4j-1.2.17.jar

Spring的AOP切面相关的包

spring-aop-4.0.0.RELEASE.jar

spring-aspects-4.0.0.RELEASE.jar

com.springsource.net.sf.cglib-2.2.0.jar

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

7.5 切入点表达式

@PointCut切入点表达式语法格式是: execution(访问权限 返回值类型 方法全限定名(参数类型列表))

  1. 匹配某全类名下,任意或多个方法。

表示匹配com.atguigu.aop.Calculator下以a打头的任意方法。并且返回值和两个参数都是int类型。

execution(public int com.atguigu.aop.Calculator.a*(int, int))

表示匹配com.atguigu.aop.Calculator下的任意方法。并且返回值和两个参数都是int类型。

execution(public int com.atguigu.aop.Calculator.*(int, int))

  1. 在Spring中只有public权限能拦截到,访问权限可以省略(访问权限不能写*)。

// 权限省略,表示任意类型的访问权限 ,但Spring现在只支持public权限

execution(int com.atguigu.aop.Calculator.*(int, int))

  1. 匹配任意类型的返回值,可以使用 * 表示

// 表示任意类型的返回值

execution(* com.atguigu.aop.Calculator.*(int, int))

  1. 匹配任意子包。

// 表示匹配com的子包

execution(* com..aop.Calculator.(int, int))

  1. 任意类型参数

// 表示第二个参数是任意类型

execution(* com.atguigu.aop.Calculator.(int,))

:可以匹配多层路径,或任意多个任意类型参数

// 表示com和aop之间可以有任意层级的包

execution(* com…aop.Calculator.*(int,int))

// 表示第一个参数是int。之后可以有任意个任意类型的参数

execution(* com.atguigu.aop.Calculator.*(int,…))

模糊匹配:

// 表示任意返回值,任意方法全限定符,任意参数

execution(* *(…))

// 表示任意返回值,任意包名+任意方法名,任意参数

execution(* .(…))

精确匹配:

// int 返回值,com.atguigu.aop.Calculator类的add方法,两个int参数

execution(public int com.atguigu.aop.Calculator.add(int, int))

切入点表达式连接:&& 、||

// 表示需要同时满足两个表达式

​ @Before(“execution(public int com.atguigu.aop.Calculator.add(int, int))”

​ + " && "

+ “execution(public * com.atguigu.aop.Calculator.add(…))”)

// 表示两个条件只需要满足一个,就会被匹配到

​ @Before(“execution(public int com.atguigu.aop.Calculator.add(int, int))”

​ + " || "

​ + “execution(public * com.atguigu.aop.Calculator.a*(int))”)

7.6 Spring切面中的代理对象

在Spring中,可以对有接口的对象和无接口的对象分别进行代理。在使用上有些细微的差别。

  1. 如果被代理的对象实现了接口。在获取对象的时候,必须要以接口来接收返回的对象。(底层使用了jdk的动态代理)

  2. 被切面拦截的代理对象,如果没有实现接口。获取对象的时候使用对象类型本身

(底层使用了cglib代理)

7.7 Spring通知的执行顺序

Spring通知的执行顺序是:

正常情况:

前置通知====>>>>后置通知=====>>>>返回值之后

异常情况:

前置通知====>>>>后置通知=====>>>>抛异常通知

7.8获取连接点信息

JoinPoint 是连接点的信息。

只需要在通知方法的参数中,加入一个JoinPoint参数。就可以获取到拦截方法的信息。

使用这个类对象在形参列表中,可以获得拦截(增强)方法的方法名和参数

注意:是org.aspectj.lang.JoinPoint这个类。

@Aspect

@Component

public class LogUtil {

​ @Before(“execution(public int com.atguigu.aop.Calculator.add(int, int))” + " || "

​ + “execution(public * com.atguigu.aop.Calculator.d*(…))”)

public static void logBefore(JoinPoint joinPoint) {

​ System.out.println(“前置 日记 :【” + joinPoint.getSignature().getName() + “】 方法调用前 。参数是:”

​ + Arrays.asList(joinPoint.getArgs()));

​ }

前面测试的代码没有变。再次执行的结果。都能拿到拦截的方法名和参数

7.9获取拦截方法的返回值和抛的异常信息

获取方法返回的值分为两个步骤:

1、在返回值通知的方法中,追加一个参数 Object result

2、然后在@AfterReturning注解中添加参数returning=“参数名”

获取方法抛出的异常分为两个步骤:

1、在异常通知的方法中,追加一个参数Exception exception

2、然后在@AfterThrowing 注解中添加参数 throwing=“参数名”

修改LogUtil切面类的代码

​ @AfterReturning(任意切入点)

public static void logAfterReturn( Object result) {

​ System.out.println(返回值:" + result);

​ }

​ @AfterThrowing(任意切入点)

public static void logThrowException( Exception exception) {

​ System.out.println(异常对象:" + exception);

​ }

7.10 Spring的环绕通知

1、环绕通知使用@Around注解。

2、环绕通知如果和其他通知同时执行。环绕通知会优先于其他通知之前执行。

3、环绕通知一定要有返回值(环绕如果没有返回值。后面的其他通知就无法接收到目标方法执行的结果)。

4、在环绕通知中。如果拦截异常。一定要往外抛。否则其他的异常通知是无法捕获到异常的。

5 在环绕通知中ProceedingJoinPoint类对象可以用来调用方法和获取任意值

在LogUtil切面类中添加环绕通知

​ @Around(value = “execution(* *(…))”)

public static Object logAround(ProceedingJoinPoint proceedingJoinPoint) {

​ //获取请求参数

​ Object[] args = proceedingJoinPoint.getArgs();

​ Object resultObject = null;

try {

​ System.out.println(“环绕前置”);

​ //调用目标方法

​ resultObject = proceedingJoinPoint.proceed(args);

​ System.out.println(“环绕返回”);

​ } catch (Throwable e) {

​ System.out.println(“环绕异常:” + e);

throw new RuntimeException(e);

​ } finally {

​ System.out.println(“环绕后置”);

​ }

​ //返回返回值

return resultObject;

7.11切入点表达式的重用

切入点表达式的重点,需要分三个步骤:

1、在切面类中定义一个空的方法

public static void pointcut1() {}

2、在方法中使用@Pointcut定义一个切入表达式

​ @Pointcut(value=“execution(public int com.atguigu.aop.Calculator.add(int, int))” + " || "

​ + “execution(public * com.atguigu.aop.Calculator.*(…))”)

public static void pointcut1() {}

3、其他的通知注解中使用方法名()的形式引用方法上定义的切入点表达式。

比如:@Before(“pointcut1()”)

7.12 多个通知的执行顺序

当我们有多个切面,多个通知的时候:

1、通知的执行顺序默认是由切面类的字母先后顺序决定。

2、在切面类上使用@Order注解决定通知执行的顺序(值越小,越先执行)

但是仅在第一次方法前置增强有效,因为是改变线程优先级

再添加另一个切面类

@Component

@Aspect

@Order(1)

另一个切面类

@Aspect

@Component

@Order(2)

7.13如何基于xml配置aop程序

aop:config

​ <aop:pointcut expression=“execution(* com.atguigu.aop.Calculator.*(…))” id=“pointcut1”/>

​ <aop:aspect order=“1” ref=“logUtil”>

​ <!-- 这是前置通知

​ method属性配置通知的方法

​ pointcut配置切入点表达式

​ -->

​ <aop:before method=任一方法名 pointcut=“execution(* com.atguigu.aop.Calculator.*(…))”/>

​ <aop:after method=任一方法r” pointcut=“execution(* com.atguigu.aop.Calculator.*(…))”/>

​ <aop:after-returning method=任一方法名

​ returning=“result” pointcut=“execution(* com.atguigu.aop.Calculator.*(…))”/>

​ <aop:after-throwing method=任一方法名 throwing=“exception”

​ pointcut=“execution(* com.atguigu.aop.Calculator.*(…))”/>

​ </aop:aspect>

​ <aop:aspect order=“2” ref=“validation”>

​ <aop:before method=“before” pointcut-ref=“pointcut1”/>

引用上面的设置属性的横切注入点

​ <aop:after method=“after” pointcut-ref=“pointcut1”/>

​ <aop:after-returning method=“afterReturning”

​ returning=“result” pointcut-ref=“pointcut1”/>

​ </aop:aspect>

​ </aop:config>

8. Spring之JdbcTemplate使用

在Spring中提供了对jdbc的封装类叫JdbcTemplate。它可以很方便的帮我们执行sql语句,操作数据库。

JdbcTemplate的使用需要在applicationContext.xml中进行配置

先创建一个数据库连接池对象 <bean id=”d**ruidDataSource” 其他的内容省略>

​ <bean id=“jdbcTemplate” class=“org.springframework.jdbc.core.JdbcTemplate”>

​ <property name=“dataSource” ref=druidDataSource**”/>引用上面创建的

1.增 删 改 使用方式同下 使用对象调用update方法 传入指定(增删改)sql语句和指定语句所需参数

​ @Test

public void test3() throws Exception {

​ String sql = “insert into employee(name,salary) values(?,?)”;

​ ArrayList<Object[]> params = new ArrayList<>();

​ params.add(new Object[] {“aaa”,100});

​ params.add(new Object[] {“bbb”,100});

​ params.add(new Object[] {“ccc”,100});

​ jdbcTemplate.batchUpdate(sql, params);

​ }

2.查一个 方法queryForObject 其他与增删改相同,但是必须创建一个对象new BeanPropertyRowMapper(传入指定类型)

public void test4() throws Exception {

​ // 查询id=5的数据库记录,封装为一个Java对象返回

​ String sql = “select id ,name ,salary from employee where id = ?”;

​ * 在queryRunner中使用的是ResultSetHandler

​ * 在Spring的jdbcTemplate中,使用RowMapper。

​ * BeanPropertyRowMapper 可以把一个结果集转成一个bean对象

​ Employee employee = jdbcTemplate.queryForObject(sql,

new BeanPropertyRowMapper(Employee.class), 5);

​ System.out.println(employee);

3.查询多个方法query 其他与增删改相同,但是必须创建一个对象new BeanPropertyRowMapper(传入指定类型)

jdbcTemplate.query(sql语句, new BeanPropertyRowMapper(Employee.class), 参数);

4.查询特殊值 方法queryForObject

jdbcTemplate.queryForObject(sql语句, 特殊值类型.class**,参数**);

9 声明式事务***(重点)

事务分为声明式和编程式两种:

声明式事务:声明式事务是指通过注解的形式对事务的各种特性进行控制和管理。

编码式(编程式)事务:指的是通过编码的方式实现事务的声明。

9.1声明式事务环境搭建

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZGdPSUvl-1574917689986)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps9.jpg)]

配置Spring的事务需要的切面类DataSourceTransactionManager

​ <bean id=“transactionManager”

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

​ <property name=“dataSource” ref=“dataSource” /> 引入写好的jdbc对象

在Spring的配置文件中加入tx名称空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0C3FYG4Q-1574917689986)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps10.jpg)]

在Spring的配置文件中

下面设置需要使用开启的事务管理对象,写入上面xml中配好的

​ <tx:annotation-driven transaction-manager=“transactionManager”/>

9.2 声明式事务@Transactional注解的多种属性
9.2.1noRollbackFor和noRollbackForClassName测试不回滚的异常

noRollbackFor=ArithmeticException.class 表示当接收到数学异常之后。不回滚

​ * noRollbackFor=ArithmeticException.class

​ * noRollbackForClassName=“java.lang.ArithmeticException” 表示当接收到指定字符串表示的全类名的异常的时候,不回滚事务

9.2.2自定义设置回滚异常

rollbackFor和rollbackForClassName回滚的异常

Spring默认回滚的是RuntimeException,运行时异常或运行时异常的子异常

​ /**

​ * spring默认回去的是运行时异常RuntimeException和RuntimeException的子异常

​ * rollbackFor=FileNotFoundException.class 表示FileNotFoundException也会回滚

​ * rollbackForClassName=“java.io.FileNotFoundException” 表示当出现配置字符串所向定的全类名的异常的时候。也会回滚事务

9.2.3事务的只读属性

readOnly只读属性 一般用在查询上 增删改使用会报错

​ * readOnly 如果值为true。表示只支持查询操作。不支持写操作

*
如果设置为false,支持全部

​ @Transactional(readOnly=true)

9.2.4事务超时属性timeout(秒为单位)

下面这种情况会抛异常,且回滚数据

​ * timeout=3表示操作不能超过3秒

​ @Transactional(timeout=3)

public void updateTwoTable() throws FileNotFoundException {

​ userDao.updateUser();

try {

​ Thread.sleep(4000);

​ } catch (InterruptedException e) {

​ e.printStackTrace();

​ }

​ bookDao.updateBook();

9.3事务的传播特性****propagation

什么是事务的传播行为: 常用propagation.REQUIRED propagation.REQUIRED_NEW

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

事务的传播行为可以由传播属性指定。Spring定义了7种类传播行为。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-grzwvFjj-1574917689986)(file:///C:\Users\尚硅谷\AppData\Local\Temp\ksohtml5496\wps11.jpg)]

9.4 xml配置式事务声明

​ <bean id=“transactionManager”

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

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

​ <tx:advice id=“tx_advice” transaction-manager=“transactionManager”>

​ tx:attributes

​ <tx:method name=“multiUpdate” propagation=“REQUIRED”/>

​ <tx:method name=“updateBook” propagation=“REQUIRES_NEW” />

​ <tx:method name=“updateUser” propagation=“REQUIRED”/>

​ <tx:method name="*" read-only=“true”/>

​ </tx:attributes>

​ </tx:advice>

​ aop:config

​ <aop:advisor advice-ref=“tx_advice” pointcut=“execution(* com.atguigu.service.*Service.*(…))” />

​ </aop:config>

10 Spring整合Web(不推荐使用)

10.1 web环境搭建

在web工程中添加Spring的jar包。

Spring的核心包

spring-beans-4.0.0.RELEASE.jar

spring-context-4.0.0.RELEASE.jar

spring-core-4.0.0.RELEASE.jar

spring-expression-4.0.0.RELEASE.jar

aop包

spring-aop-4.0.0.RELEASE.jar

spring-aspects-4.0.0.RELEASE.jar

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

JDBC-ORM包

spring-jdbc-4.0.0.RELEASE.jar

spring-orm-4.0.0.RELEASE.jar

spring-tx-4.0.0.RELEASE.jar

Spring的web整合包

spring-web-4.0.0.RELEASE.jar

测试包

spring-test-4.0.0.RELEASE.jar

整合Spring和Web容器分两个步骤:

1、在web.xml配置文件中配置org.springframework.web.context.ContextLoaderListener监听器监听 ServletContext的初始化

2、在web.xml配置文件中配置contextConfigLocation上下文参数。配置Spring配置文件的位置,以用于初始化Spring容器

在web.xml中配置

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContext.xml</param-value>

​ org.springframework.web.context.ContextLoaderListener

listener>

10.2获取WebApplicationContext上下文对象的方法如下:

在创建的动态项目的servlet中获取webSpring容器,其他操作系统

方法一(推荐):

WebApplicationContextUtils.getWebApplicationContext(getServletContext())

方法二(不推荐):

getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

x:attributes>

​ <tx:method name=“multiUpdate” propagation=“REQUIRED”/>

​ <tx:method name=“updateBook” propagation=“REQUIRES_NEW” />

​ <tx:method name=“updateUser” propagation=“REQUIRED”/>

​ <tx:method name="*" read-only=“true”/>

​ </tx:attributes>

​ </tx:advice>

​ aop:config

​ <aop:advisor advice-ref=“tx_advice” pointcut=“execution(* com.atguigu.service.*Service.*(…))” />

​ </aop:config>

10 Spring整合Web(不推荐使用)

10.1 web环境搭建

在web工程中添加Spring的jar包。

Spring的核心包

spring-beans-4.0.0.RELEASE.jar

spring-context-4.0.0.RELEASE.jar

spring-core-4.0.0.RELEASE.jar

spring-expression-4.0.0.RELEASE.jar

aop包

spring-aop-4.0.0.RELEASE.jar

spring-aspects-4.0.0.RELEASE.jar

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

JDBC-ORM包

spring-jdbc-4.0.0.RELEASE.jar

spring-orm-4.0.0.RELEASE.jar

spring-tx-4.0.0.RELEASE.jar

Spring的web整合包

spring-web-4.0.0.RELEASE.jar

测试包

spring-test-4.0.0.RELEASE.jar

整合Spring和Web容器分两个步骤:

1、在web.xml配置文件中配置org.springframework.web.context.ContextLoaderListener监听器监听 ServletContext的初始化

2、在web.xml配置文件中配置contextConfigLocation上下文参数。配置Spring配置文件的位置,以用于初始化Spring容器

在web.xml中配置

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContext.xml</param-value>

​ org.springframework.web.context.ContextLoaderListener

listener>

10.2获取WebApplicationContext上下文对象的方法如下:

在创建的动态项目的servlet中获取webSpring容器,其他操作系统

方法一(推荐):

WebApplicationContextUtils.getWebApplicationContext(getServletContext())

方法二(不推荐):

getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值