Spring总结

1.Spring概述

spring是一个后台框架、管理服务的框架,主要功能是代码托管(将所有的代码交给spring来管理),什么时候要new对象,new对象时需要什么东西,都是由spring解决的。

spring是一个企业级应用的开源开发框架,目标是简化java企业级应用开发,以控制反转(IOC)、依赖注入(DI)、和面向切面编程(AOP)为内核,包含7个大的模块。

在实际开发中,通常服务器端采用三层体系架构,分别为表现层(web)、业务逻辑层(service)、持久层(dao)。

Spring 对每一层都提供了技术支持,在表现层提供了与 Struts2 框架的整合,在业务逻辑层可以管理事务和记录日志等,在持久层可以整合 Hibernate 和 JdbcTemplate 等技术。

Spring 具有简单、可测试和松耦合等特点,不仅可以用于服务器端的开发,也可以应用于任何 Java 应用 反射和动态代理.html 的开发中。

1.1 spring特点、优势

(1)方便解耦,简化开发

Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。

(2)方便集成各种优秀框架

Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。

(3)降低 Java EE API 的使用难度

Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。

(4)方便程序的测试

Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。

(5)AOP 编程的支持

Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。

(6)声明式事务的支持(声明事务用一个注解就可以搞定)

只需要通过配置就可以完成对事务的管理,而无须手动编程。

1.2 spring体系结构

Spring 框架采用分层架构,根据不同的功能被划分成了多个模块,这些模块大体可分为 Data Access/Integration、Web、AOP、Aspects、Messaging、Instrumentation、Core Container 和 Test,如图 1 所示。

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

数据访问/集成层包括 JDBC、ORM、OXM、JMS 和 Transactions 模块,具体介绍如下。

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

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

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

  • JMS 模块:指 Java 消息服务,包含的功能为生产和消费的信息。

  • Transactions 事务模块:支持编程和声明式事务管理实现特殊接口类,并为所有的 POJO。

(2)Web 模块

Spring 的 Web 层包括 Web、Servlet、Struts 和 Portlet 组件,具体介绍如下。

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

  • Servlet模块:包括 Spring 模型—视图—控制器(MVC)实现 Web 应用程序。

  • Struts 模块:包含支持类内的 Spring 应用程序,集成了经典的 Struts Web 层。

  • Portlet 模块:提供了在 Portlet 环境中使用 MV C实现,类似 Web-Servlet 模块的功能。

(3)Core Container(核心容器)

Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 Expression Language 表达式语言模块组成,具体介绍如下。

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

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

  • Context 上下文模块:建立在核心和 Beans 模块的基础之上,它是访问定义和配置任何对象的媒介。ApplicationContext 接口是上下文模块的焦点。

  • Expression Language 模块:是运行时查询和操作对象图的强大的表达式语言。

(4)其他模块

Spring的其他模块还有 AOP、Aspects、Instrumentation 以及 Test 模块,具体介绍如下。

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

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

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

  • Test 模块:支持 Spring 组件,使用 JUnit 或 TestNG 框架的测试。

注:七大模块(面试高频)

1.核心容器(Spring Core)

核心容器提供spring框架的基本功能。

Core模块中有Beans,BeanFactory,BeanDefinitions,ApplicationContext等几个重要的概念。 Beans为Spring里的各种对象,一般配置在Spring配置文件中BeanFactory为创建Beans的FacotorySpring通过BeanFactory加载各种BeansBeanDefinition为Bean在配置文件中的定义一般要定义id与classApplicationContext代表配置文件Core模块依赖Spring的Core类库

2.应用上下文(Spring Context)

spring上下文是一个配置文件,向spring框架提供上下文信息,spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。

3.Spring面向切面编程(Spring AOP)

通过配置管理特性,Spring AOP模块直接向面向方面的编程功能集成到了Spring框架中,所以,可以很容易地使Spring框架管理的任何对象支持AOP,Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。通过使用Spring AOP不用依赖EJB组件,就可以将声明性事务管理集成到应用程序中。

4.JDBC和DAO模块(Spring DAO)(封装了一些数据库层面的底层操作)

JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常层次处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的简化了需要编写的代码数量,比如打开和关闭链接。

5.对象实体映射(Spring ORM)

Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和IBatis SQL Map等,所有这些都遵从Spring的通用事务和DAO异常层次结构。

6.Web模块(Spring Web)

Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。所以Spring框架支持与Struts集成,Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

7.MVC模块(Spring Web MVC)(实现MVC三层架构)

MVC框架是一个全功能的构建Web应用程序的MVC实现,通过策略接口,MVC框架变成为高度可配置的,MVC容纳了大量视图技术,其中包括JSP、POI等,模型由Java Bean来构成,存放于m当中,而视图是一个接口,负责实现模型,控制器表示逻辑代码,是c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境,Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。

2.项目搭建

2.1 创建项目

2.1.1 创建maven项目

导入依赖:四个基础包(core、beans、context、expression)(webmvc)

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.9.RELEASE<version>
</dependency>

2.1.2 准备好测试类

2.1.3 准备spring核心配置文件,applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 前面两行是协议 比如:你在后面需要用到哪一个标签或功能,需要提前在前面声明一下-->  
<beans      xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    <!-- 由 Spring容器创建该类的实例对象,一个bean表示要装配一个实体类-->
    <bean id="user" class="pojo.User" />
</beans>

id:给管理对象起的名字,唯一标识

class:对应的类,这个类交给spring托管

name:同上,但是可以重复,可以用特殊字符

2.1.4 通过容器获取对象

	 //定义spring配置文件的路径
		 String xmlPath = "applicationContext.xml";
		// 初始化Spring容器,加载配置文件(根据配置文件加载了spring容器)
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过容器获取User实例,括号里的name就是配置文件里定义的id
        User user = (User) applicationContext.getBean("user");

把要用到的实体类存到容器里,用的时候直接找容器要,不用new

3.IOC和DI(面试高频)

高内聚,低耦合

高内聚:一个类严格完成自己的功能,内部很团结。

低耦合:类与类之间的关系很小。

控制反转,依赖注入

IOC 控制反转(Inversion of Control), 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转,这就是 Spring 的 IoC 思想。对象与对象之间松耦合,利于功能复用。

(从程序员的手上反转到了程序里面,由代码去做操作)

DI 依赖注入(Dependency Injection)和控制反转含义相同,它们是从两个角度描述的同一个概念。

当某个 Java 实例需要另一个 Java 实例时,传统的方法是由调用者创建被调用者的实例(例如,使用 new 关键字获得被调用者实例),而使用 Spring 框架后,被调用者的实例不再由调用者创建,而是由 Spring 容器创建,这称为控制反转。

Spring 容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者,这样,调用者通过 Spring 容器获得被调用者实例,这称为依赖注入。

3.1 属性 setter 注入

指 IoC 容器使用 setter 方法注入被依赖的实例。通过调用无参构造器或无参 static 工厂方法实例化 bean 后,调用该 bean 的 setter 方法,即可实现基于 setter 的 DI。

3.2 构造方法注入

指 IoC 容器使用构造方法注入被依赖的实例。基于构造器的 DI 通过调用带参数的构造方法实现,每个参数代表一个依赖。

通过更改对dao的使用理解控制反转原理

4.容器

Spring 提供了两种 IoC 容器,分别为 BeanFactoryApplicationContext

IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转,这就是 Spring 的 IoC 思想。

4.1 BeanFactory

BeanFactory 是基础类型的 IoC 容器,它由 org.springframework.beans.facytory.BeanFactory 接口定义,并提供了完整的 IoC 服务支持。简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。

BeanFactory 接口有多个实现类,最常见的是 org.springframework.beans.factory.xml.XmlBeanFactory,它是根据 XML 配置文件中的定义装配 Bean 的。

创建 BeanFactory 实例时,需要提供 Spring 所管理容器的详细配置信息,这些信息通常采用 XML 文件形式管理。其加载配置信息的代码具体如下所示:

BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D://applicationContext.xml"));

4.2 ApplicationContext

ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文。该接口的全路径为 org.springframework.context.ApplicationContext,它不仅提供了 BeanFactory 的所有功能,还添加了对 i18n(国际化)、资源访问、事件传播等方面的良好支持。

ApplicationContext 接口有两个常用的实现类,具体如下。

4.2.1 ClassPathXmlApplicationContext

该类从类路径 ClassPath 中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作,具体如下所示。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);

在上述代码中,configLocation 参数用于指定 Spring 配置文件的名称和位置,如 applicationContext.xml。

4.2.2 FileSystemXmlApplicationContext

该类从指定的文件系统路径中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作,具体如下所示。

ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);

它与 ClassPathXmlApplicationContext 的区别是:在读取 Spring 的配置文件时,FileSystemXmlApplicationContext 不再从类路径中读取配置文件,而是通过参数指定配置文件的位置,它可以获取类路径之外的资源,如“F:/workspaces/applicationContext.xml”。

在使用 Spring 框架时,可以通过实例化其中任何一个类创建 Spring 的 ApplicationContext 容器。

BeanFactory 和 ApplicationContext 都是通过 XML 配置文件加载 Bean 的。

二者的主要区别在于,如果 Bean 的某一个属性没有注入,则使用 BeanFacotry 加载后,在第一次调用 getBean() 方法时会抛出异常,而 ApplicationContext 则在初始化时自检,这样有利于检查所依赖的属性是否注入。

即前者会在调用对象时加载装配对象,后者会在容器初始化时加载所有对象。

4.3 创建对象的三种方式

4.3.1 空参构造(必须掌握)

4.3.2 静态工厂(了解)

创建spring配置文件

<bean id="u1" class="pojo.UserFactory" factory-method="getUser"></bean>

创建静态工厂类

public static User getUser() {
		return new User();
	}

创建测试类

// 初始化Spring容器,加载配置文件(根据配置文件加载了spring容器)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过容器获取User实例
        User user = (User) applicationContext.getBean("u1");
        System.out.println(user);

4.3.3 实例工厂(了解)

创建spring配置文件

<!-- 调用工厂 -->
  	<bean id="u2" factory-bean="factory" factory-method="getUser2"></bean>
  	<!-- 先把工厂加载出来 -->
    <bean id="factory" class="pojo.UserFactory"></bean>

创建实例工厂类

public static User getUser() {
		return new User();
	}
public User getUser2() {
		return new User();
	}

创建测试类

// 初始化Spring容器,加载配置文件(根据配置文件加载了spring容器)
   ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过容器获取User实例
        User user = (User) applicationContext.getBean("u2");
        System.out.println(user);

5.依赖注入(面试高频)

5.1 set方法(重要)

  • 基本类型

  • 集合、属性

    • 数组

    • list

    • set

    • map

    • properties

    • null

  • 引用类型

5.2 构造方法

  • name

  • value

  • index

  • type

5.3 p命名空间(原理为set)

5.4 c命名空间(原理为构造)

5.5 sepl(spring expression language)spring表达式语言

 

 

6.bean的作用域和模块化(面试高频)

6.1 scope属性

6.1.1 singleton 作用域

singleton 是 Spring 容器默认的作用域,当一个 Bean 的作用域为 singleton 时,Spring 容器中只会存在一个共享的 Bean 实例,并且所有对 Bean 的请求,只要 id 与该 Bean 定义相匹配,就只会返回 Bean 的同一个实例。

通常情况下,这种单例模式对于无会话状态的 Bean(如 DAO 层、Service 层)来说,是最理想的选择。

在 Spring 配置文件中,可以使用 <bean> 元素的 scope 属性,将 Bean 的作用域定义成 singleton,其配置方式如下所示:

<bean id="person" class="com.mengma.scope.Person" scope="singleton"/>

6.1.2 prototype 作用域

使用 prototype 作用域的 Bean 会在每次请求该 Bean 时都会创建一个新的 Bean 实例。因此对需要保持会话状态的 Bean(如 Struts2 的 Action 类)应该使用 prototype 作用域。

在 Spring 配置文件中,要将 Bean 定义为 prototype 作用域,只需将 <bean> 元素的 scope 属性值定义成 prototype,其示例代码如下所示:

<bean id="person" class="com.mengma.scope.Person" scope="prototype"/>

6.2 初始化和销毁

  • init-method

<bean id="person" class="pojo.Person" scope="prototype" init-method="init" destroy-method="destory"></bean>
  • destory-method
<bean id="person" class="pojo.Person" scope="prototype" init-method="init" destroy-method="destory"></bean>

6.3 模块化配置

  • import
<import resource="xxx.xml"/>

7.Spring Bean的生命周期

Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。

而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。每次客户端请求 prototype 作用域的 Bean 时,Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。

了解 Spring 生命周期的意义就在于,可以利用 Bean 在其存活期间的指定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,会在 Bean 被初始化后和被销毁前执行一些相关操作。

Spring 容器中 Bean 的生命周期流程如图 1 所示。

Bean 生命周期的整个执行过程描述如下。

1)根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。

2)利用依赖注入完成 Bean 中所有属性值的配置注入。

3)如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。

4)如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

5)如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。

7)如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。

8)如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。

10)如果在 <bean> 中指定了该 Bean 的作用范围为 scope="singleton",则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 <bean> 中指定了该 Bean 的作用范围为 scope="prototype",则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。

11)如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

8.自动装配和注解开发

8.1 自动装配

除了使用 XML 和 Annotation 的方式装配 Bean 以外,还有一种常用的装配方式——自动装配。自动装配就是指 Spring 容器可以自动装配(autowire)相互协作的 Bean 之间的关联关系,将一个 Bean 注入其他 Bean 的 Property 中。

spring会在上下文中自动寻找,自动给bean装配属性。

三种方式

要使用自动装配,就需要配置 <bean> 元素的 autowire 属性。

8.1.1 在xml中显示的配置(基础)

8.1.2 隐式的自动装配(重要)

1.autowire属性自动装配

byName

<bean id="person" class="pojo.Person" autowire="byName">
    
    <bean id="car" class="pojo.Car">
    	<property name="name" value="123"></property>
    </bean>

byType

<bean id="person" class="pojo.Person" autowire="byType">
    
    <bean id="car" class="pojo.Car">
    	<property name="name" value="123"></property>
    </bean>

2.注解自动装配

导入约束(context)

xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd">

配置注解支持

<!-- 开启注解 -->
<context:annotation-config/>

@Autowired

用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。

@Autowired
	Car car;
<bean id="car" class="pojo.Car">
    	<property name="name" value="宝马"></property>
    </bean>

@Qualifier

与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。

@Autowired
	@Qualifier("car123")
	Car car;
    <bean id="car" class="pojo.Car">
    	<property name="name" value="宝马"></property>
    </bean>
    <bean id="car123" class="pojo.Car">
    	<property name="name" value="兰博基尼"></property>
    </bean>
    <bean id="car222" class="pojo.Car">
    	<property name="name" value="蹦蹦"></property>
    </bean>

@Resource(java原生注解)

其作用与 Autowired 一样。其区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配。

@Resource 中有两个重要属性:name 和 type。

Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为 Bean 实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。

如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。

注意:jdk版本问题

8.1.3 在java中显示配置

@Configuration(扔给spring托管)

作用:该类作为配置,不打也可以

打上的话,你配置的获得类对象默认是单例,不配置,就不是单例

@Bean

作用:相当于配置文件中的<bean></bean>

注意:单例 源码

8.2 注解开发

spring4之后,使用注解开发,需要导入aop包

jdk1.5支持注解,spring2.5支持注解

步骤:

1.导入aop包

2.添加指定约束

3.扫描指定包

@Component

组件,把该类交给spring托管

可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。

@Repository

数据库

用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

@Service

服务层

通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

@Controller

控制层

通常作用在控制层(如 Struts2 的 Action),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

@Autowired

自动装配

用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。

@Value

赋值

@Scope

范围、作用域

@PostConstruct

在构造方法之后执行

@PreDestory

在销毁之前执行

比较:

  • 优点:注解开发简化代码,方便

  • 缺点:复杂类型注入不方便,不便于维护

9.spring整合单元测试

9.1 添加junit依赖

<dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

9.2 添加spring-test依赖

相当于省略了创建类的过程(先得到容器,再通过容器得到想要的对象)

 <dependency>
   	 	<groupId>org.springframework</groupId>
    	<artifactId>spring-test</artifactId>
    	<version>5.2.9.RELEASE</version>
	</dependency>

9.3 

SpringJUnit4ClassRunner:这个类是spring整合单元测试的一个类

classpath:后面写配置文件的名字,从类路径下加载这个文件

@Runwith():启动

@ContextConfiguration():上下文的配置文件,括号中写上配置文件的名字

@Runwith和@ContextConfiguration:这两步自动帮你打开容器

10.类加载

  • 类加载指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象

  • 当一个变量被修饰成static final,并在编译期就能确定其值,也就是常量,那么通过类名.变量名访问该变量时不会加载该类(也就是访问常量并不会初始化这个类)

10.1 类初始化时机

类从加载到虚拟机内存开始,到卸载出内存为止,生命周期包括:加载(Loading),验证(Verification),准备(Preparation),解析(Resolution),初始化(Initialization),使用(Using)和卸载(Unloading)七个阶段。其中,验证、准备、解析三个部分统称为连接(Linking)

  1. new对象、调用类的静态方法或者静态变量时

  2. 虚拟机启动时,加载用户指定的main方法的所在类

  3. 通过反射调用某个类

  4. 初始化一个类时先初始化它的父类

  5. 初始化某个类的子类

中心思想:初始化时机为该类首次主动使用

以下情况不会初始化

1、通过子类类名调用父类静态代码,不会触发子类的初始化。(初始化父类)

2、通过数组来创建对象不会触发此类的初始化。(初始化数组和数组中的泛型,不会让本类做初始化)

3、通过调用静态常量不会触发初始化。

 

10.2 类加载器

  1. Bootstrap ClassLoader,被称为引导(也称为原始或根)类加载器。它负责加载 Java的核心类。在Sun的JVM中,当执行java.exe的命令时使用-Xbootclasspath选项或使用-D选项指定sun.boot.class.path系统属性值可以指定加载附加的类。根类加载器非常特殊,它并不是java.lang.ClassLoader的子类,而是由JVM自身实现的。(主要作用:加载jvm自己本身,加载核心包)

  2. Extension ClassLoader,被称为扩展类加载器,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或由java.ext.dirs系统属性指定的目录)中的JAR的类包。

  3. System ClassLoaser,被称为系统(也称为应用)类加载器,它负责在JVM启动时,加载来自命令java中的-classpath选项或java.class.path系统属性,或CLASSPATH环境变量所指定的JAR包和类路径。

11.反射

11.1 概念

官方解释:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

简单理解:反射就是直接通过字节码文件class,去使用它的变量,方法,和构造。

11.2 使用步骤

  1. 获得class对象

  2. 从class中获取信息

11.3 获取class对象

共有三种方式:

  1. 使用Class类的forName(类的全名),该方法需要传入参数,参数为某个类的全名(包名+类名)

Class.forName("com.test.User");

2.调用某个类的class属性获取其对应的Class对象

User.class;

3.调用某个对象的getClass()方法

User.getClass();

11.4 从Class中获取信息

获取对应类中的构造器,类型为Constructor

1.获得所有public修饰的构造方法

public Constructor[] getConstructors();

2.获得所有构造方法,包括私有

public Constructor[] getDeclaredConstructors();

3.获取指定的public修饰构造方法,参数是该构造方法里参数的类型的class对象

public Constructor<T> getConstructor(Class<?>... parameterTypes);

例如:

4.获取指定构造方法,包括私有

public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);

使用:拿到构造方法后,用Constructor对象调用newInstance()方法就可以调用该构造方法创建对象。例如

获得私有构造方法也可以使用,在newInstance操作前设置一下构造方法的访问权限:

constructor.setAccessible(true);

获取方法,类型为Method

1.获取指定的public方法

public Method getMethod(String methodName ,Class<?>… parameterTypes) //第一个参数为方法名,后面参数为形参的类型的class

2.获取所有public方法

public Method[] getMethods()

3.获取指定的方法,包括私有

public Method getDeclaredMethods(String name ,Class<?>… parameterTypes)

4.获取所有方法,包括私有

public Method[] getDeclaredMethods()

使用:invoke(对象名,实参)

获取变量,类型为Field

1.获取指定的public变量

public Field getField(String name)

2.获取所有public变量

public Field[] getFields()

3.获取指定的变量,包括私有

public getDeclaredField(String name)

4.获取所有变量,包括私有

public Field[] getDeclaredFields()

使用:set(对象,值):设置属性;get(对象):获取属性值

11.5 结合配置文件的使用

11.6 操作数组

可以通过java.lang.reflect下的Array类来操作数组

  • static Object new Instance(Class<?> componentType,int... length):创建一个具有指定的元素类型、指定维度的数组

  • static xxx get(Object array,int index)

  • static void set(Object array,in index,xxx value)

12.aop(面试高频)

12.1 反射基础

12.2 静态代理和动态代理

  • 代理模式

  • 增删改查

静态代理

  • 不带接口

  • 带接口

举例:mybatis里讲动态代理之前举的例子

优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.

缺点:代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

动态代理:

  • 通过Proxy创建动态代理对象

    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) //三个参数分别为目标对象的类加载器,目标对象所有接口,实现了InvocationHandler接口的类

  • InvocationHandler接口,重写invoke方法

作用:

  1. 解决多个方法中调用了一个通用功能的问题

  2. 解耦

再举个例子

1.创建接口

2.创建接口的实现类

3.实现InvocationHandler接口(处理器)

4.编写代理工厂

5.测试

调用代理对象的方法时,其实走的就是重写的invoke方法,invoke方法里我们去调用了共用的方法,调用对象本身方法时就用到了反射

思考:为什么jdk动态代理,被代理类一定要实现接口?

  • 生成的代理类默认继承了proxy类,所以可以可以做一些底层操作,但是因为java单继承,所以这个代理对象没办法获得被代理对象的方法,这时代理对象就必须要通过实现接口的方式来获得被代理对象的方法

  • 举例:美团跑腿

  • 应用

    • dbutils 包装数据

    • spring 装配对象

12.3 aop概念

面向切面编程(AOP)和面向对象编程(OOP)类似,也是一种编程模式。Spring AOP 是基于 AOP 编 程模式的一个框架,它的使用有效减少了系统间的重复代码,达到了模块间的松耦合目的。

AOP 的全称是“Aspect Oriented Programming”,即面向切面编程,它将业务逻辑的各个部分进行隔 离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。

AOP 采取横向抽取机制,取代了传统纵向继承体系的重复性代码,其应用主要体现在事务处理、日志管 理、权限控制、异常处理等方面。

目前最流行的 AOP 框架有两个,分别为 Spring AOP 和 AspectJ。

Spring AOP 使用纯 Java 实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类 植入增强的代码。

AspectJ 是一个基于 Java 语言的 AOP 框架,从 Spring 2.0 开始,Spring AOP 引入了对 AspectJ 的支 持。AspectJ 扩展了 Java 语言,提供了一个专门的编译器,在编译时提供横向代码的植入。

为了更好地理解 AOP,就需要对 AOP 的相关术语有一些了解,这些专业术语主要包含 Joinpoint、 Pointcut、Advice、Target、Weaving、Proxy 和 Aspect,它们的含义如下表所示。

12.4 动态代理的方式

  • 原生开发- 接口-基于jdk

  • cglib- 类

  • javasist-class

  • springapi

  • aspectj(重要)

    • xml

    • 注解

通知类型

  • 前置通知(在方法调用前执行)

  • 后置通知(在方法调用之后执行,如果出现异常不会调用)

  • 环绕通知(执行前做一次,执行后做一次)

  • 异常拦截通知(发生异常之后执行)

  • 后置通知(无论是否有异常都会调用)

Spring 通知的 5 种类型

Aspectj具体实现

AspectJ 是一个基于 Java 语言的 AOP 框架,它扩展了 Java 语言。Spring 2.0 以后,新增了对 AspectJ 方式的支持,新版本的 Spring 框架,建议使用 AspectJ 方式开发 AOP。

导入依赖:需要aop和aspectj,同时添加aop约束

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

使用 AspectJ 开发 AOP 通常有两种方式:

  • 基于 XML 的声明式。

  • 基于 Annotation 的声明式。

基于XML的声明式

基于 XML 的声明式是指通过 Spring 配置文件的方式定义切面、切入点及声明通知,而所有的切面和通知都必须定义在 aop:config 元素中。

1.导入依赖:需要aop包和aspectj,同时添加aop约束

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.6</version>
</dependency>
xmlns:aop="http://www.springframework.org/schema/aop"

 xsi:schemaLocation="
  http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"

2.目标对象

<!-- 目标对象 -->
    <bean id="dao" class="dao.UserDaoMysql"></bean>

3.配置通知对象

<bean id="myAdvice" class="dao.SpAdvice"></bean>

4.配置切入点

<aop:config>
		<aop:pointcut expression="execution(* dao..*Mysql.*(..))" id="pc"/>
	</aop:config>    

<!-- 通过aop:config配置 -->
	<aop:config>
		<!-- 切入点 -->
		<aop:pointcut id="pc" expression="execution( * dao..*Mysql.*(..))"/>
		<!-- 切面 -->
		<aop:aspect	ref="myAdvice">
			<aop:before method="before" pointcut-ref="pc"/>
			<aop:after-returning method="after" pointcut-ref="pc"/>
			<aop:around method="around" pointcut-ref="pc"/>
			<aop:after-throwing method="afterException" pointcut-ref="pc"/>
			<aop:after method="afterall" pointcut-ref="pc"/>
		</aop:aspect>
	</aop:config>

5.测试

//得到容器
		 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		//要到执行的对象
		 UserDao udm = (UserDao)applicationContext.getBean("dao");
		udm.select();

基于 Annotation 的声明式

<!-- 开启注解 -->
	<context:annotation-config/>
	<!-- 动态代理 --> 
	<aop:aspectj-autoproxy/>
@Aspect
public class SpAdvice {
	@Pointcut("execution( * dao..*Mysql.*(..))")
	public void pc() {
		
	}
	
	@org.aspectj.lang.annotation.Before("SpAdvice.pc()")
	public void before() {
		System.out.println("前置通知");
	}
	
	@After("SpAdvice.pc()")
	public void after() {
		System.out.println("后置通知");
	}
	
	@Around("SpAdvice.pc()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("环绕前");
		Object object = pjp.proceed();
		System.out.println("环绕后");
		return object;
	}
	
	@AfterThrowing("SpAdvice.pc()")
	public void afterException() {
		System.out.println("异常通知");
	}
	
	@AfterReturning("SpAdvice.pc()")
	public void afterall() {
		System.out.println("无论是否由异常都会通知");
	}
}

注:每个通知前配置切入点,后期不方便修改和维护,可以用@Pointcut注解来解决,注解下面创建一个空方法。

通知前调用(类名.空方法名)名即可找到切入点。

13.spring整合mybatis

什么是 MyBatis-Spring?

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。

知识基础

在开始使用 MyBatis-Spring 之前,你需要先熟悉 Spring 和 MyBatis 这两个框架和有关它们的术语。这很重要——因为本手册中不会提供二者的基本内容,安装和配置教程。

MyBatis-Spring 需要以下版本:

安装

1.导入依赖

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>2.0.5</version>
</dependency>
<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>2.0.5</version>
		</dependency>

<!--这里使用jdbc方式连接,所以导入jdbc包。如果需要用连接池,就导入对应连接池的包 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>5.2.9.RELEASE</version>
		</dependency>

2.准备mybatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

	<settings>
		<setting name="logImpl" value="Log4j"/>
	</settings>
	<!-- 别名 -->
	<typeAliases>
		<typeAlias alias="student" type="pojo.Student"/>
	</typeAliases> 
	
	<!-- 数据库环境 -->
  <environments default="development">
    <environment id="development">
    <!-- 使用JDBC的事务管理 -->
      <transactionManager type="JDBC"/>
      <!-- 数据库连接池 -->
      <dataSource type="POOLED">
       <!-- MySQL数据库驱动 -->
        <property name="driver" value="com.mysql.jdbc.Driver"/>
         <!-- 连接数据库的url -->
        <property name="url" value="jdbc:mysql://localhost:3306/xsh?characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <!-- <mapper resource="Test.xml"/> -->
    <!-- <package name="mapper"/> -->
  </mappers>
</configuration>

3.准备pojo、mapper.xml、mapper.java

4.准备数据库源文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/xsh?characterEncoding=utf8
jdbc.username=root
jdbc.password=root

5.准备spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <!-- 
	1.读取数据源的配置
	2.配置数据源
	3.配置sqlSessionFactory工厂
	4.配置sqlSession    
     -->
    
    <!-- 工厂 session mapper -->
    
    <!-- 第1步:加载数据库配置项 -->
    <context:property-placeholder location="classpath:db.properties"/>
    <!-- 第2步:配置数据源,这里用的是jdbc的方式。数据源可以替换为任意的数据库连接池,只需要导入对应的jar包即可 -->
    <bean id = "dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    	<property name="driverClassName" value="${jdbc.driver}"></property>
    	<property name="url" value="${jdbc.url}"></property>
    	<property name="username" value="${jdbc.username}"></property>
    	<property name="password" value="${jdbc.password}"></property>
    </bean>
    
    <!-- 第3步:配置SqlSessionFactory -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 配置mybatis核心配置文件 -->
		<property name="configLocation" value="classpath:mybatis.xml"></property>
		<!-- 配置数据源(连接数据库) -->
		<property name="dataSource" ref="dataSource"></property>
		
		
		<!-- <property name="mapperLocations" value="com/gsh/mapper/*.xml"></property> -->
	</bean>
	
	
	<!-- 第4步:配置sqlSession -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<!-- 通过构造的方式注入sqlSessionFactory -->
		<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
	</bean>
	
    <!-- 上面扫描mapper只能扫描xml文件,如果想扫描java文件,用下面的写法 -->
	<!-- 以bean的方式注册到容器,扫描所有的mapper接口 
		自己装配到容器,直接扫描mapper.java,省去了配置sqlSession
-->
	<!-- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.gsh.mapper"/>
	</bean> -->
	
    <!-- 扫描单个mapper -->
	<!-- <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
		<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
		<property name="mapperInterface" value="com.gsh.mapper.StudentMapper"></property>
	</bean> -->
    
</beans>

整合进阶

1.将mybatis文件中的<mappers></mappers>去掉

2.在spring配置文件中找到SqlSessionFactoryBean(这个相当于mybatis整个的配置),可在其中配置mapper、别名

补充:还可以用import引入xml文件(模块化开发,这样可以使每个文件功能区分的很清)

<import resource=""/>

用连接池整合

添加数据库连接池依赖

<!-- 数据库连接池 -->
		<dependency>
			<groupId>com.mchange</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.5.5</version>
		</dependency>

修改spring配置文件

1.配置数据源

<!-- 第2步:配置数据源,这里用的是jdbc的方式。数据源可以替换为任意的数据库连接池,只需要导入对应的jar包即可 
    		连接数据库默认走的是连接池
    		连接数据库源的方式:1.走连接池 2.不走连接池 3.jndi
    -->
    <bean id = "dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    	<property name="driverClass" value="${jdbc.driver}"></property>
    	<property name="jdbcurl" value="${jdbc.url}"></property>
    	<property name="user" value="${jdbc.username}"></property>
    	<property name="password" value="${jdbc.password}"></property>
    </bean>

2.根据数据源配置工厂

<!-- 第3步:配置SqlSessionFactory -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 配置mybatis核心配置文件 -->
		<property name="configLocation" value="classpath:mybatis.xml"></property>
		<!-- 配置数据源(连接数据库) -->
		<property name="dataSource" ref="dataSource"></property>
		
		<!-- 只能指定xml文件(指定mapper的位置) -->
		<property name="mapperLocations" value="com/gsh/mapper/*.xml"></property>
	</bean>

3.扫描整个mapper包

<!-- 以bean的方式注册到容器,扫描所有的mapper接口 -->
	 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.gsh.mapper"/>
	</bean>

14.spring事务

事务的实现方式

  • 编码式(通过代码去写)

  • 声明式

tx包和约束

  • 添加约束

要开启spring的事务处理功能,在spring的配置文件中创建一个DataSourceTransactionManager对象。

<!-- 将处理事务的类注册到容器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 事务管理依赖于数据源(数据库) -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>

配置事务通知

<!-- 配置事务的通知 -->
	<!-- transaction-manager="" 事务所依赖的管理器 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<!-- 配置属性 -->
		<tx:attributes>
			<!-- 主要配置针对某一个方法的事务的相关特性 -->
			<!-- 
			isolation="DEFAULT" 隔离级别
			propagation="REQUIRED" 传播行为
			read-only="false" 只读,不需要更改东西 (例如:查询),默认是false 
			timeout="-1" 过期时间
			rollback-for="" -Exception
			no-rollback-for="" +Exception
			 -->
		
			<!-- name中的transfer是业务层代码中的某一个方法 -->
			<tx:method name="transfer" propagation="REQUIRED"/>
		</tx:attributes>
	</tx:advice>

事务的传播行为

配置事务的切入

<!-- 配置事务的切入  对事务的增强配置到切入点-->
	<aop:config>
		<!-- 配置切入点 -->
		<aop:pointcut expression="execution(*.com.gsh.……)" id="pc"/>
		<!-- 配置切面 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
	</aop:config>

补充:spring种propagation的7种事务配置

在声明式的事务处理中,要配置一个切面,其中就用到了propagation,表示打算对这些方法怎么使用事务,是用还是不用,其中propagation有七种配置,REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。默认是REQUIRED。

Spring中七种Propagation类的事务属性详解:

  1. REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 (默认)

  2. SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

  3. MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。

  4. REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

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

  6. NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

  7. NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

    注意:这个配置将影响数据存储,必须根据情况选择。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值