编写Spring第一个程序

Spring是一种开源框架,通过使用它可以大大降低企业应用程序的复杂性。Spring是一种非常完善的框架,几乎涉及WEB开发中的每一层,但是在开发中通常使用Spring开发业务逻辑层,资深的Java EE开发人员会发现Spring框架似曾相识,它其实没有太多的新东西,只是抽象了大量Java EE应用中常用代码,将他们抽象成一个框架,框架中充满了各种设计模式的应用,如单例模式、工厂模式、抽象工厂模式、命令模式、职责链模式、代理模式等,通过使用Spring可以大幅度提高开发效率,课可以保证整个应用具有良好的设计。Spring像是一种中间容器,向上可以与MVC框架无缝整合,向下可以与各种持久层框架无缝整合。

重点内容:

了解Spring架构和为什么使用Spring

下载和安装Spring

在集成开发工具中使用Spring

开发Spring的第一个程序

Spring概述

1.为什么使用Spring

Spring是一种轻量级框架,轻量级是指该框架技术是非入侵式的,用Spring中开发的系统类不需要依赖于Spring中的类,它不需要容器支持。

在没使用Spring之前,如果在业务逻辑层中访问数据访问层,需要在业务逻辑层中创建数据访问层的对象,然后使用该对象调用DAO方法。

使用这种方式使业务逻辑层和数据访问层的耦合性非常高,当数据访问层程序发生改动时,则还需要来改动业务访问层的程序,这样就增加了程序员的工作量。

当Spring出现以后,这种问题就得到了很好的解决。业务逻辑层和数据访问层之间是注入的关系,在业务逻辑层中并不需要创建数据访问层的对象。

2.Spring技术介绍

Spring是一种非常完整的技术,也就是说只使用Spring技术也能开发项目。但是在实际开发中并不这样做,只是让Spring做业务逻辑层,因为Spring的业务处理能力是非常强大的。

在Spring技术中,最经典的就是IoC和AOP技术。其中IoC是指依赖注入,通过使用该技术可以使业务逻辑层和数据访问层解耦合。

Spring的另一个重要技术那就是AOP,通过使用AOP可以很容易的完成切面开发。在后面的学习中将最这两个重要技术进行详细讲解。

Spring开发环境的搭建

1.手动搭建

手动搭建Spring开发环境需要两步,分别是下载和安装。下载Spring可以通过Spring官方网站的下载频道进行下载,下载地址为“http://repo.spring.io/release/org/springframework/spring/”,在其中选择下载Spring Framework。下载后是一个zip文件,将其解压,可以看到在它下面有很多目录。

其中libs是Spring的核心目录,在其中保存了Spring开发生成的JAR文件。docs是帮助目录,其中包含了Spring教程和API文档。

1.手动搭建

Spring的优点就是不依赖于任何服务器和框架,安装Spring时只需要将提供的JAR文件设置到CLASSPATH中。在Spring框架中有很多中JAR文件,它对应着Spring的各种应用。在Spring的研发中,也为初学者考虑到,创建了一个spring-core-版本.jar包,它位于libs目录下,在该包中Spring基本使用类。除了要使用该包外,还要使用到commons-logging.jar包,下载地址:http://commons.apache.org/proper/commons-logging/。

如果使用Spring进行WEB开发,其安装是更简单的,只需要将这两个包复制到WEB应用的WEB-INF\lib目录下。

2.使用Eclipse自动搭建

在Eclipse中集成了Spring项目开发,通过它是非常容易的搭建Spring开发环境的,它的步骤如下:

(1)选中要进行Spring开发的项目,右击选择Build Path,Configure Build Path...,将需要的架包加入项目中,如下:

开发Spring的HelloWorld程序

1.开发Spring程序的步骤

Spring的主要功能是对业务逻辑层进行操作,为了简单需要,在该第一个程序中,采用Java项目的方式进行开发,在其中只给出业务逻辑层。

Spring开发是有严格的步骤的,无论项目简单和复杂,都要按照这个步骤进行操作。在开发业务逻辑层时,一定要定义业务接口和业务实现类,这是Spring开发的第一步。然后在Spring配置文件中对业务实现类进行配置。最后是开发客户端程序,进行项目测试。

2.编写业务接口

先来开发业务接口,在该业务接口中定义了SayHello方法。通过该方法创建一个接收姓名信息,然后返回问候语句功能。

package com.tufujie.service;
public interface HelloService {
public String SayHello(String name);
}

3.编写业务实现类

开发完业务接口后,就继续来编写业务实现类。业务实现类要实现业务接口,从而实现业务接口中的抽象方法。

public class HeloServiceImpl implements HelloService {
public String SayHello(String name) { return "Hello!!!"+name;
}
}

4.配置业务实现类

配置业务实现类,需要在项目的src目录下创建一个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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="hello" class="com.tufujie.service.HeloServiceImpl">
</bean>
</beans>

5.编写客户端进行测试

到目前为止,Spring的程序已经开发完毕,在本小节中就通过一个客户端程序来对Spring的程序进行测试。通过该客户端程序调用业务实现类中的业务方法。

public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlAppl
icationContext("applicationContext.xml")
HelloService helloService=(HelloService)
factory.getBean("hello");
String name="Tom";
System.out.println(helloService.SayHello(name));
}

控制反转

控制反转是Spring的核心技术之一,它是英文名称为“Inversion of Control”,所以在很多地方将控制反转缩写为IoC。Spring的很多功能都是基于控制反转技术的。在上一章中学习Spring的第一个程序时,就是一个简单的IoC程序。在本章中将继续学习Spring的这一核心技术。

重点内容:

Spring容器和容器中的Bean

掌握各种依赖注入

Bean特性介绍

ApplicationContext的使用

IoC容器

1.Bean工厂接口

Bean工厂接口在前面的学习中已经见到过,它的全称接口名为“org.springframework.beans.factory.BeanFactory”,该接口程序可以在Spring的核心JAR包spring.jar中找到。在Spring程序中,BeanFactory实际上是IoC的代表者,通过使用该接口对其中的Bean进行管理。

在Spring中,定义了多种Bean工厂接口的实现类,它们的使用是有很大不同的。其中比较常用的就是XmlBeanFactory,使用该类可以XML文件的形式来描述对象和对象之间的关系。在学习第一个Spring程序时,就是以XML文件的形式对业务实现类对象进行配置的。

2.实例化容器

要想使用IoC容器,就需要对容器进行实例化操作,通过实例化后的容器对象就可以访问其中的Bean对象。当使用XML配置文件的方式对Bean对象进行管理时,实例化容器的过程其实也是加载配置文件的过程。实体化容器其实也是加载配置文件的过程实例化容器有多种方式,在本节中就来对这些方式进行一一讲解。

首先来看第一种通过系统路径进行实例化的方式,该方式是和IO流操作非常相似的,在其中使用FileSystemResource类构造函数来指定配置文件的位置。第二种方式是通过ClassPath查找配置文件,该方法的前提是配置文件必须在ClassPath环境配置中。第三种方式是通过上下文实例化,这里要使用到BeanFactory接口的子接口Application Context。

3.多配置文件的使用

当开发的项目很大时,使用一个Spring配置文件是比较复杂的,其中可能具有几千行的配置信息,在其中查找某一个Bean对象的配置是非常困难的。所以在Spring中可以定义多个配置文件,将一类配置放置在一个文件中。

当一个项目中具有多个Spring配置文件时,就会出现一个问题,那就是该如何实例化容器。在Spring中,设计了两种方式。一种是使用ApplicationContext实现类的重载构造函数,将所有配置文件的路径组成字符串数据做为参数,例如:

ApplicationContext context =new  ClassPathXmlApplicationContext(new String[]{ "applicationContext.xml","applicationContext-part2.xml"});
BeanFactory factory = context;

4.配置Bean

在学习第一个程序后,已经见过了如何配置Bean。配置Bean是通过使用<bean>标记对其进行配置,其中class属性指定Bean的完整路径。每一个Bean中都有一个或者多个id属性,id是Bean的标识符,在当前IoC容器中必须是唯一的。如果一个Bean有多个id,则将其他id在本质上被认为是别名。

为Bean指定别名在特定环境下是非常必要的,例如我们指定操作老师的DAO的名称为“teacherDAO”,但是在对学生操作时也会使用到该DAO,这时候就可以为它起一个别名为“studentDAO”进行使用。定义别名除了定义多个id属性外,还可以在Bean定义后补充,这里要使用到<alias>标记。例如完成如上功能的代码为:

<alias name=" teacherDAO" alias=" studentDAO "/>

5.使用容器实例化Bean

对容器实例化后,使用容器对象调用getBean方法,在其中使用id属性值做为参数,就可以实例化指定的Bean。例如:

HelloServicehelloService = (HelloService)factory.getBean("hello");

这里使用到了根据Java的反射机制创建一个实际的对象。可以看到我们使用容器实例化Bean是非常简单的,但是在Spring的内部操作是比较复杂的。在Spring中,实例化Bean有三种方式,分别是使用构造器、使用静态工厂方法和使用实例工厂方法。

6.容器常用方法

BeanFactory容器中除了getBean方法中外,还有其他几种常用的方法,这里我们对这些方法进行简单的介绍。

boolean containsBean(String)
Object getBean(String, Class)
Class getType(String name)
boolean isSingleton(String)
String[] getAliases(String)

依赖注入

1.Setter方法注入

使用Setter方法进行注入是依赖注入的一种方式。在使用Bean中,定义需要注入属性的Setter方法,然后在Spring配置文件中给出该属性的值,最后在客户端程序中就可以访问这些属性值。先来看一个Bean程序。

<bean id="student" class="com.tufujie.service.Student">
<property name="name">
<value>Tom</value>
</property>
<property name="age">
<value>21</value>
</property>
</bean>

2.构造函数注入

虽然在Spring中提倡使用Setter方法的方式进行注入,但是使用构造函数是依赖注入非常重要的方式之一。有些程序员更倾向于使用构造函数的方式进行注入,是因为使用这种方式可以将所有属性一次性注入。

使用构造函数进行注入的方式时,必须在Bean程序中声明有参构造函数,其中的参数就是要注入的属性。看下面的Bean程序代码。

<bean id="teacher" class="com.tufujie.service.Teacher">
<constructor-arg type="java.lang.String">
<value>Jerry</value>
</constructor-arg>
<constructor-arg type="int">
<value>32</value>
</constructor-arg>
</bean>

3.注入其他Bean

在前面的学习中,介绍了两种注入的方式,在其中都是通过基本类型和字符串类型进行举例说明的。除此之外,采用将bean中指定属性的值设置为对容器中的另外一个bean的引用的方式,可以在一个Bean中注入其他Bean。该操作是通过<ref>标记对完成,将其放在<constructor-arg>标记对或者<property>标记对中。从这里也可以看出注入其他Bean也是有两种注入方式的,这里我们只以使用Setter方法的方式进行注入。

<bean id="UserDAOImpl" class="com.tufujie.dao.UserDAOImpl"></bean>
<bean id="userService" class="com.tufujie.service.UserServiceImpl">
<property name="userDAO">
<ref bean="UserDAOImpl"/>
</property>
</bean>

4.内部Bean

在Java基本语法中有局部变量的概念,局部变量只能在所在的语句块中使用。同样在Spring中有“局部”Bean,它的标准名称为内部Bean。内部Bean是指注入的Bean只能被它所在的Bean使用,不能再被其他Bean所注入。内部Bean是不需要id属性和name属性的,因为它能做被所在Bean使用,就算设定了id属性和name属性,容器也会将其省略掉。

<bean id="userService"
class="com.tufujie.service.UserServiceImpl">
<property name="userDAO">
<bean class="com.tufujie.dao.UserDAOImpl"/>
</property>
</bean>

5.注入集合

在Java中,集合包括List、Set和Map三种,在Spring除了能够对这三种集合能够注入操作外,还包括Properties映射文件。在Spring配置文件中,使用<list/>、<set/>、<map/>及<props/>标记来对应集合。在这里,我们只给出配置文件代码,读者可以在光盘中查看到Bean代码,在Bean中定义了四种集合变量。

6.空字符串和null值的处理

在Spring中,对空字符串和null值进行注入有不同的。当对空字符串进行注入时,只需要在其中的<value>标记对中不写入任何内容。例如:

<bean class="Teacher">
<property name="name"><value></value></property>
</bean>

它相当于Java中的:teacher.setName(“”);

当对null值进行注入时,需要使用<null>标记,例如:

<bean class="Teacher">
<property name="name"><null/></property>
</bean>

它相当于Java中的:teacher.setName(null);

7.依赖注入的简写形式

在前面的举例中,读者可能会发现当注入值或者其他Bean时,都要在其中使用到<value>标记或者<ref>标记。Spring为了简化该操作,在<property>、<constructor-arg>和<entry>标记中定义了value属性和ref属性来替代<value>标记和<ref>标记。这里我们仅一使用Setter方法方法注入基本数据类型数据为例,如果使用原<value>标记的方式,形式为:

<property name="name">
<value>Tom</value>
</property>

如果使用value属性的方式,则形式为:<property name="name" value="Tom"/>

8.不完全依赖

在前面学习注入其他Bean时,当Bean甲被依赖注入到Bean乙中时,在Bean乙中就可以使用Bean甲进行调用方法。在其中Bean甲是要在Bean乙之前实例化的。

但是实际开发中有这样一种情况,需要Bean甲在Bean乙之前实例化,但是在Bean乙中是不需要使用Bean甲的,这种情况下就可以使用不完全依赖注入。这种情况在数据库开发中比较常见,例如注册数据驱动必须在所有操作之前完成。

不完全依赖是通过<bean>标记中的depends-on属性完成的,它的属性值就是要在所在Bean之前实例化的Bean。例如:

<bean id="student" class="Student" />

<bean id="teacher" class="Teacher" depends-on=" student "/>

9.自动装配

在Spring中,具有自动装配的方式注入其他Bean,使用该方式可以简化注入Bean的复杂配置。自动装配是通过<bean>标记的autowire属性定义的,该属性可选的属性值有五种,它们各自代表不同的自动装配方式。

◆ no,代表不使用自动装配。

◆ byName ,根据属性名自动装配。

◆ byType, 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。

◆ constructor 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。

◆ autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。

Bean作用域

1.Singleton作用域

Singleton作用域是Bean的默认作用域。当一个Bean的作用域为singleton,时,那么在Spring IoC容器中只会存在一个共享的Bean实例。也就是说所有对Bean的请求,只要id与该Bean定义相匹配,则只会返回bean的同一实例。Bean的单一实例存储在单利缓存中,请求和引用该Bean时,将自动调用该缓存中的对象实例。

因为Bean的默认作用域就是Singleton,所以将Bean定义成Singl eton有三种方式,最简单的就是什么都不定义。除此之外,还有如下两种方式:

<bean id="teacher" class="com.Teacher" scope="singleton"/>

<bean id=" teacher " class="com.Teacher" singleton="true"/>

2.Prototype作用域

Prototype作用域是和Singleton作用域相对的。当一个Bean设置为Prototype作用域时,则该Bean每被请求或者引用一次,都会创建一个Bean实例对象。

将Bean的作用域设定为Prototype有两种方式,是和Singleton作用域设定非常相似的,它有两种方式,如下:

<bean id="teacher" class="com.Teacher" scope="prototype"/>

<bean id=" teacher " class="com.Teacher" singleton="flase"/>

3.Request作用域

request、session和global session的作用域是和前面的两种作用域有很大不同的,它们只能应用在Web的项目中。Web中的容器实例化是和前面学过的实例化是有所不同的,它要使用XmlWebApplicationContext来查找Spring配置文件。

在Web中,每次HTTP请求就对应一个request对象。将Bean的作用域设定为request,就表示该Bean只在当前请求中有效。不同请求中的Bean是互相看不到状态变化的。当处理请求结束时,request作用域的Bean实例也就被销毁。request作用域的Bean的配置如下所示:

<bean id="userDAO" class=" com.tufujie.dao.UserDAOImpl" scope="request"/>

4.Session作用域

在Web中,每次HTTP会话就对应一个Session对象。将Bean的作用域设定为session,就表示该Bean只在当前会话中有效。在用户操作比较多的网站中,例如购物网站中,通常一个用户对应一个Session对象。在这种项目中,通过将用户共用的Bean设置为session作用域,这就可以使一个用户不能看到其他用户的状态。

当一次会话结束时,session作用域的Bean实例就会被销毁。session作用域的Bean的配置如下所示:

<bean id="userDAO" class=" com.tufujie.dao.UserDAOImpl" scope="session"/>

5.global session作用域

global session作用域和Session作用域是非常相似的,它在实际开发中是非常少用的。在global session作用域的bean中被限定为全局portlet Session的生命周期范围内。global session作用域的Bean的配置如下所示:

<bean id="userDAO" class=" com.tufujie.dao.UserDAOImpl" scope="globalSession"/>

6.自定义作用域

在Spring 2.0及以上版本中,Spring的作用域中种类是可以扩展的,也就是说我们不但可以使用前面讲解的五种以定义作用域,还可以进行自定义作用操作。

在Spring框架中,作用域是由Scope接口定义的,它接口的全称接口名为org.springframework.beans.factory.config.Scope,在JAR包可以看到该接口的代码。所有的作用域都是实现Scope接口,同样自定义作用域也要实现该接口,并且要实现该接口中的方法,分别是底层存储机制获取和删除对象方法。

自定义完作用域类后,还需要对其进行配置,然后在其他Bean中才能使用。由于该知识点是比较复杂的,在实际开发中使用的也不是很多,这里就仅对功能进行简单讲解。

面向切面编程

在本章中继续学习Spring的第二大功能,那就是面向切面编程。在前面学习Java时,我们知道Java是一门面向对象的语言,在学习Java之前,读者可能还学习过面向过程的语言,这些都是编程思想。面向切面编程在一定程度上弥补了面向对象编程的不足,面向对象编程是对父类子类这种纵向关系编程,而面向切面编程是在方法的前后进行横向关系编程。面向切面编程的缩写是AOP,在本章中就来对AOP的技术进行详细讲解。

重点内容:

了解面向切面编程概念

通过注解的方式进行面向切面编程

通过配置的方式进行切面编程

面向切面编程简介

1.面向切面编程概念

首先来看切面,如果读者是山西人的话,看到切面的概念,肯定会首先想到刀削面。Spring中的“切面”就是刀削面中的那把刀,使用这把刀可以将一个事物一分为二。Spring中的“切面”就是这个作用,它可以将一个程序分为两部分,并在中间加入自己想做的事,并且它可能不仅仅对一个程序,而且是一个包下的所有程序。

在一个程序使用切面,通常是对程序中的方法进行操作,方法调用和处理异常等时间段就称为连接点。在Spring的面向切面编程中,一个连接点就代表一个方法的执行。在一个连接点中,有分为很多个切入点,例如方法调用前,方法调用后等。在Spring中,执行切面编程是通过拦截器的概念,当运行到某一切入点时,会告诉拦截器,这就是通知的概念。

2.面向切面编程的功能

Spring AOP是使用纯Java编写的,所以在我们的程序中可以无缝使用,并很容易完成对它的扩展。在目前的Spring的面向切面编程中仅支持以方法做为连接点。如果读者向完成成员变量的连接点操作,可以扩展Spring框架。只所在在Spring框架中仅仅做了方法的功能,是因为在实际开发中应用最多的就是它,对于成员变量的操作是非常少的。

在后面的学习中,就重要来学习Spring中使用面向切面编程对程序中的方法进行操作。通过这种操作,是方法的功能更加丰富。

使用注解方式进行AOP开发

1.启动AspectJ的支持

要想在Spring的面向切面开发中使用注解方式,就需要使用到AspectJ组件技术。要使用AspectJ技术首先要导入AspectJ相关的两个JAR,分别是aspectjweaver.jar 和aspectjrt.jar,它们位于lib/aspectj目录下。

除了需要导入AspectJ相关JAR外,还需要在Spring的配置文件,通常是applicationContext.xml文件,在其中加入相应的配置,其代码如下所示。

<aop:aspectj-autoproxy/>

2.声明切面

在完成上一小节的内容的基础上,在Spring中开发Bean程序时,需要在Bean类的前面加入@AspectJ,从而标明该类是Spring中的切面。

@Aspect

public class BooksServiceImpl{

}

开发完Bean后,同样需要在Spring配置文件中进行配置,例如:

<bean id="booksServiceImpl" class="BooksServiceImpl"></bean>

可以看到对声明切面的Bean进行配置时,和普通的Bean是没有任何区别的。

3.声明切入点

切入点决定了连接点关注的内容,使得我们可以控制通知什么时候执行。在前面学习中已经知道面向切面编程仅对方法执行,所以切入点也仅仅是判断哪些方法需要进行面向切面编程。

声明切入点是需要使用@Pointcut注解,在后面给出切入点表达式,定义关注哪些方法的执行。后面还要给出一个切入点名称,它通过一个没有返回值的普通方法来构成。例如:

@Pointcut("execution(* com.tufujie.dao..*.*(..) ")

private void allMethod(){};

其中“@Pointcut”是声明切入点的固定格式。“execution(* com.tufujie.dao..*.*(..)”是切入点表达式,它的使用是AspectJ的核心技术,在后面会对其进行讲解。“allMethod”是切入点的名称。

4.声明通知

声明通知的作用是告诉程序当在切入点的什么时刻执行下面的方法。目前的通知方式有前置通知、返回后通知、抛出异常后通知和后通知。其中前置通知是指在切入点方法运行之前进行通知,从而执行下面的方法,使用的是@Before注解。例如:

@Before("allMethod ()")

private void myBeforeMethod() {

}

其中“@Before”是声明通知的固定格式,“allMethod”是切入点的名称,和声明切入点时相对应。下面的“myBeforeMethod”方法是定义的要执行的方法。

切入点

1.切入点指定者

在进行Spring面向切面编程时,支持在切入点表达式中使用很多种AspectJ切入点指定者,其中使用最多的就是前面使用到的execution,通过它来匹配方法执行的连接点。除了execution切入点指定者外,还包括如下几种比较常用的。

◆ within:通过限定匹配特定类型确定连接点。

◆ this:通过指定类型的实例确定连接点。

◆ target:通过目标对象确定连接点。

◆ args:通过参数确定连接点。

2.合并切入点

在Java中有“&&”、“||”和“!”三种短路逻辑运算符,在切入点表达式中也可以使用这三种逻辑运算符,其中最常用的就是“||”,它表示两边的方法都可以声明切入点,例如:

@Pointcut("execution(* com.tufujie.dao.*.*(..)) || execution(* com.tufujie.service.*.*(..))")

上面的切入点表达式表示不管是dao包下的接口还是service包下的接口内的所有方法都会定义成后面的切入点,从而使它们都能够进行面向切面开发。

3.切入点表达式

在前面的学习中,读者可能对切入点表达式有很大疑惑。在本节中就通过execution切入点指定者来讲解切入点表达式,其语法格式为如下。

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern))

其中“modifiers-pattern”表示访问修饰符,它是可选的。“ret-type-pattern”表示返回类型,它是必须的,当使用“*”时,表示可以是任意返回类型。“declaring-type-pattern”表示全程限定的类型名,它也是可选的。“name-pattern”表示限定的方法名,它是必须的,使用“*”可以匹配全部或者某一种类方法。“param-pattern”表示参数,当为空时表示无参数方法,当为“..”时表示匹配任意数量参数的方法,在参数中也可以指定特定的类型。

通知

1.返回后通知

返回后通知是指当匹配的方法执行retrun语句返回值时进行通知,它使用“@AfterReturning”注解进行声明,基本形式为:

@AfterReturning("allMothod()") //声明通知

public void myAfterReturningMethod(){ //定义通知方法

}

从形式上可以看出,这种返回后通知是和前面学习的前置通知非常相似的。

在使用返回后通知时,在通知方法中经常想要得到方法的返回值,这就需要使用到returning子句。

2.抛出后通知

抛出后通知是指当执行匹配方法抛出异常后进行通知,它使用“@AfterThrowing”注解进行声明,基本形式为:

@AfterThrowing("allMothod()") //声明通知

public void myAfterThrowingMethod(){ //定义通知方法

}

抛出后通知是和返回后通知有很大相似的地方的,在通知方法中也可以得到匹配方法抛出的异常,这里要使用到throwing子句。通过使用throwing子句也可以对匹配方法通过抛出异常进行限制,如果不想限制,可以使用所有异常的父类Throwable为类型。

3.后通知

后通知是指当当匹配的方法执行结束后通知,它使用“@After”注解进行声明。需要注意的是,方法的结束有多种情况,例如正常运行结束、返回值后结束和发生异常,不管是哪种方式的结束都会进行后通知。后通知的基本形式为:

@After("allMothod()") //声明通知

public void myAfterMethod(){ //定义通知方法

}

后通知和前置通知非常相似的,也是非常容易学习的,这里就不在举例讲解。

4.环绕通知

环绕通知是前置通知和后通知的结合体,使用环绕通知可以使一个方法的前后都执行通知方法。并且通过环绕通知可以决定方法什么时候执行,如何执行和是否执行。

环绕同时是使用“@Around”注解声明的,在其中指定切入点名称。在通知方法中必须要有一个ProceedingJoinPoint类型的参数。在通知方法内可以使用ProceedingJoinPoint类型参数调用proceed方法可以导致潜在的连接点方法的执行。proceed方法具有参数为Object对象数组的重载方式,通过该方法可以传入方法执行时候的参数。环绕通知的基本形式如下:

@Around("allMothod()") //声明通知
public void myAfterMethod(ProceedingJoinPoint pjp){
Object retVal = pjp.proceed();
return retVal;
}

5.通知顺序

当进行数据库开发时,有这样一种情况,在执行数据库操作执行后,不但要关闭数据库资源,还要关闭数据库。当我们通过切面编程完成该功能时,就要写两个通知方法,这就出现通知顺序的问题,也就是在同一时刻有两个通知方法要执行。

如果两个通知方法在同一个切面中,该通知顺序是非常简单的,根据声明顺序来确定执行顺序,声明在前,则执行通知方法的时候也在前。

如果两个通知方法不在同一切面中,这时不进行设置,则执行顺序是不确定的,这在实际开发中就可能出现问题。在线程中,我们可以通过设置线程的优先级来设置线程执行的优先性。同样通知方法也有优先级,在Spring中可以实现“org.springframework.core.Ordered”接口,通过该接口可以获取和设置通知方法的优先级。

使用配置方式进行AOP开发

1.配置声明切面

在配置方式进行AOP开发中,可以将声明切面的类做为普通的类配置到Spring容器中,从而做为一个Bean进行操作,不过这需要给出相应的schema支持。

声明切面是通过<aop:aspect>标记对来声明的,在其中使用id属性指定切面名称,使用ref属性指定切面类Bean的id名称。例如:

<aop:config>
<aop:aspect id="myAspect" ref="aspectJXML">
...
</aop:aspect>
</aop:config>
<bean id="aspectJXML" class=" com.tufujie.service.AspectJXML">
</bean>

切面类Bean是其他Bean一样,都可以由Spring容器进行管理配置和依赖注入操作。

2.配置声明切入点

使用配置方法进行AOP开发时,声明切入点有两种配置方法,根据作用范围的不同,切入点可以分为全局切入点和局部切入点。声明切入点是通过<aop:pointcut>标记对声明的,当进行全局切入点声明式,要求将<aop:pointcut>标记对直接配置到<aop:config>标记对,这样就可以使多个切面和通知共享该切入点。全局切入点的声明如下:

<aop:config>
<aop:pointcut id="allMothod" expression="execution(* com.tufujie.dao.*.*(..))"/>
</aop:config>

声明局部切入点时需要将<aop:pointcut>标记对配置到表示切面的<aop:aspect>标记对中,从而在该切面中声明切入点。

3.配置声明通知

通知的种类在前面的学习中已经讲解过,使用不同方式进行AOP开发是不影响通知种类的。这里我们仍然通过前置通知将进行讲解,它需要使用<aop:before>标记对进行配置,它需要配置在切面中,也就是<aop:aspect>标记对中,例如:

<aop:config>
<aop:aspect id="myAspect" ref="aspectJXML">
<aop:pointcut id="allMothod" expression="execution(* com.tufujie.dao.*.*(..))"/>
<aop:before pointcut-ref="allMothod" method="myBeforeMethod"/>
</aop:aspect>
</aop:config>
<bean id="aspectJXML" class=" com.tufujie.service.AspectJXML">
</bean>

面向切面编程API介绍

1.处理切入点

先来看一下在Spring中是如何处理切入点的。在Spring中定义了切入点模型,该模型的核心处理接口为“org.springframework.aop.

Pointcut”,使用该接口可以使切入点和通知相分离,从而使一个切入点可以被多个通知使用。切入点模型的Pointcut接口的代码为:

public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}

2.处理通知

在本节中继续学习Spring中是如何处理通知的。在Spring中,每一种通知都是一个Bean。在其中可以设置类共享或者实例共享的参数,从而设定一个通知实例是被所有被通知的对象共享,还是被每一个被通知对象独占。Spring中已经定义了多种通知类型,这个在前面的学习中已经讲解过。这里我们先来看一下最简单的前置通知是如何实现的。

前置通知是通过MethodBeforeAdvice接口完成的,它的代码为:

public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method m, Object[] args, Object target) throws Throwable;
}

3.使用AOP的工厂Bean

在学习Spring的依赖注入时,经常会提到依赖注入的Bean工厂。同样在进行面向切面编程时,也有AOP的工厂Bean。通过使用面向切面的工厂Bean,可以对应用的切入点和通知进行管理。处理AOP的工厂Bean的全称接口名为“org.springframework.aop.framework.Proxy

FactoryBean”。

在Spring中大量使用了代理设计模式,使用ProxyFactoryBean接口引用调用getObject方法将产生一个工厂Bean的代理对象,它就是AOP代理。使用AOP代理的一个直接好处就是可以让IoC容器操作切入点和通知。

ProxyFactoryBean类中具有很多属性,这些属性一部分是自定义的,另一大部分是继承来来的。通过使用这些属性可以指定希望代理的目标对象和指定是否使用CGLIB。

在Spring中进行JDBC编程

1.Spring中的数据库操作封装类

Spring中的数据库操作封装类是JdbcTemplate,它位于“org.

springframework.jdbc.core”包下。使用该类可以完成数据库的连接和关闭,从而简化JDBC操作。JdbcTemplate将完成JDBC核心处理流程,例如SQL语句的创建、执行,而把SQL语句的生成以及查询结果的提取工作留给程序员写的应用代码。

创建JdbcTemplate类对象,通常要使用到DataSource接口参数,DataSource接口将在下一小节中进行讲解。JdbcTemplate类和普通的Bean一样,可能直接使用Java代码进行实例化,也可以通过使用Spring的IoC容器进行实例化。

2.数据源接口

数据源接口也就是DataSource接口,通过使用该接口可以创建一个数据库连接。DataSource接口也称为数据源接口,在Spring中有多种创建数据源的方式,例如JNDI、第三方连接池等。在本书中主要来通过Spring配置的方式建立数据源。在前面学习JDBC和Hibernate时已经知道,要想连接数据库,最少要知道数据库的驱动、url、用户名和密码,所以在配置DataSource接口时需要给出这些信息。

<bean id="dataSource" class="org.springframework.jdbc.datas
ource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
。。。。
</bean>

3.执行SQL语句

学习完Spring中的数据库操作封装类和数据源接口,现在就可以结合使用它们进行数据库开发,先来看一下如何进行基本的SQL语句运行。

private JdbcTemplate jt;
private DataSource dataSource;
public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; }
public void doExecute() {
jt = new JdbcTemplate(dataSource);
jt.execute("create table user (id integer, name varchar(100))");
}

4.更新数据库操作

更新数据库操作中包括插入、修改和删除三种三种,这三种操作都是通过update方法完成的。在update方法中给出SQL语句参数,从而完成相应的数据库操作。

private JdbcTemplate jt;
private DataSource dataSource;
public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
} public void doUpdate() {
jt = new JdbcTemplate(dataSource);
jt.update("insert into user values (1,'Tom')");
}

5.查询数据库操作

创建数据表,并且向其中插入数据后,就可以通过查询操作将数据表中的数据查询出来。在Spring的封装数据库中查询数据的方法有很多,这里我们使用其中的两个,分别是查询一个数据和查询所有数据。

public String doGetName() {
jt = new JdbcTemplate(dataSource);
String name=(String)jt.queryForObject("select name
from user where id=1", String.class);
return name;
} public List doGetNames(){
jt = new JdbcTemplate(dataSource);
List list=jt.queryForList("select name from user");
return list;
}

Spring个人总结的更多相关文章

  1. 基于spring注解AOP的异常处理

    一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...fin ...

  2. 玩转spring boot——快速开始

    开发环境: IED环境:Eclipse JDK版本:1.8 maven版本:3.3.9 一.创建一个spring boot的mcv web应用程序 打开Eclipse,新建Maven项目 选择quic ...

  3. Spring基于AOP的事务管理

                                  Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...

  4. [Spring]IoC容器之进击的注解

    先啰嗦两句: 第一次在博客园使用markdown编辑,感觉渲染样式差强人意,还是github的样式比较顺眼. 概述 Spring2.5 引入了注解. 于是,一个问题产生了:使用注解方式注入 JavaB ...

  5. 学习AOP之透过Spring的Ioc理解Advisor

    花了几天时间来学习Spring,突然明白一个问题,就是看书不能让人理解Spring,一方面要结合使用场景,另一方面要阅读源代码,这种方式理解起来事半功倍.那看书有什么用呢?主要还是扩展视野,毕竟书是别 ...

  6. 学习AOP之深入一点Spring Aop

    上一篇<学习AOP之认识一下SpringAOP>中大体的了解了代理.动态代理及SpringAop的知识.因为写的篇幅长了点所以还是再写一篇吧.接下来开始深入一点Spring aop的一些实 ...

  7. 学习AOP之认识一下Spring AOP

    心碎之事 要说知道AOP这个词倒是很久很久以前了,但是直到今天我也不敢说非常的理解它,其中的各种概念即抽象又太拗口. 在几次面试中都被问及AOP,但是真的没有答上来,或者都在面上,这给面试官的感觉就是 ...

  8. 为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?

    今年我一直在思考web开发里的前后端分离的问题,到了现在也颇有点心得了,随着这个问题的深入,再加以现在公司很多web项目的控制层的技术框架由struts2迁移到springMVC,我突然有了一个新的疑 ...

  9. Spring之旅(2)

    Spring简化Java的下一个理念:基于切面的声明式编程 3.应用切面 依赖注入的目的是让相互协作的组件保持松散耦合:而AOP编程允许你把遍布应用各处的功能分离出来形成可重用的组件. AOP面向切面 ...

  10. Spring之旅

    Java使得以模块化构建复杂应用系统成为可能,它为Applet而来,但为组件化而留. Spring是一个开源的框架,最早由Rod Johnson创建.Spring是为了解决企业级应用开发的复杂性而创建 ...

随机推荐

  1. firefox ie chrome 设置单元格宽度 td width 有bug,不能正常工作。以下方式可以解决

    1. firefox ie chrome 设置单元格宽度 td width 有bug,不能正常工作. 如果是上面一行 和下面一行是分别属于两个table,但是他们的列需要对齐,也就是说分开画的,然后设 ...

  2. 就要从SDG离职了

    在知乎上看到有个提问,你为什么从盛大离职.我八月份在盛大游戏实习之间,下个星期准备辞职迎接新的挑战.本文也将提到我在盛大实习的经历以及离职的原因.当然,不会涉及很多SDG内部的管理以及技术上的秘密. ...

  3. centos 7 lNMP 安装之php 篇

    1.准备工作 安装依赖包 yum install -y gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype ...

  4. 基于Jquery 的 Chart

     Flot  Flot一个纯javascript绘画库,基于jQuery开发.它能够在客户端根据任何数据集快速生成图片.目前只能绘制线状图和柱状. Flot  jQuery  jQchart  基于C ...

  5. C++ 关联容器详解——从内部结构到应用

    关联容器不同于顺序容器的是:顺序容器底层用数组实现,为线性结构:关联容器在实现中,用到的非线性存储方式: 顺序容器是通过元素在容器中的位置顺序存储和访问元素,而关联容器是通过键(key)存储和读取元素 ...

  6. what is the purpose of channel coding?(信道编码的作用?)

    信道.信道编码及其作用 1.信道(channel) 信道和通信电路并不等同,用来表示向某一个方向传送信息的媒体.因此一条通信线路往往包含一条发送信道和一条接收信道. 从通信的双方信息交互方式看有三个基 ...

  7. cron服务 ubuntu

    linux 定时执行crontab  crontab -e 进入一个vi 编辑界面 在最后一行加上 */30 * * * * netstat > /tmp/net.log 表示每隔30分就执行n ...

  8. Arcgis 10.1中空间连接功能

    空间链接的作用:将面上的所有点的值加起来取平均值.赋值给面属性.(我们可以定义右击——定义合并规则 连接要素的字段映射参数中指定的合并规则仅适用于连接要素中的属性,且仅适用于多个要素与目标要素匹配 ( ...

  9. linux驱动系列之调试环境搭建一

    2014年刚开始学习linux时,搭建环境花了很多时间.当时最熟悉的是单片机如Mag16和stm32,依据以往学习单片机的经验肯定要用下载器下载程序,但是我找了很久没有比较好的IDE,不像Mag16有 ...

  10. mysql分表与分区表

    mysql分表与分区表 转自:http://blog.51yip.com/mysql/949.html   一,什么是mysql分表,分区 什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具 ...