IDEA项目实践——Spring当中的切面AOP

系列文章目录

IDEA创建项目的操作步骤以及在虚拟机里面创建Scala的项目简单介绍

IDEA项目实践——创建Java项目以及创建Maven项目案例、使用数据库连接池创建项目简介

IDEWA项目实践——mybatis的一些基本原理以及案例

IDEA项目实践——动态SQL、关系映射、注解开发

IDEA项目实践——Spring框架简介,以及IOC注解

文章目录

系列文章目录

一 AOP介绍

1.0 不使用切面编程额开发方式

项目 aop_leadin2

1.1 AOP简介

1.2 AOP的作用

 1.3 两种代理

1.4 面向切面编程的好处

 1.5 AOP编程术语(掌握)

 1.6 AspectJ对AOP的实现(掌握) 

1.6.0 AspectJ简介

1.6.1 AspectJ 的通知类型(理解)

1.6.2 AspectJ 的切入点表达式(掌握)

二 不使用AOP的开发方式的案例讲解

2.1 加入Maven项目spring-aop-leadin1

 2.2 创建接口SomeService

 2.3 编辑接口的实现类SomeServiceImpl

2.3.1 优化实现类的方案一

2.3.2 优化实现类的方案二

2.4 编辑测试类 

 三 使用JDK动态代理开发AOP项目

3.1 创建Maven项目【此处使用的是JDK动态代理】

3.2 加入一个 handler文件夹原来存放JDK代理

3.3 编辑一个测试类二

 四 使用spring-aop-aspectj的框架来实现AOP编程

4.1 创建Maven项目

4.2 导入依赖 

4.3  AspectJ 基于注解的 AOP 实现(掌握)

(1) 实现步骤

A、 Step1:定义业务接口与实现类​编辑

B、Step2:定义切面类

C、Step3:声明目标对象切面类对象

D、 Step4:注册 AspectJ 的自动代理

E、 Step5:测试类中使用目标对象的 id

(2) [掌握]@Before 前置通知-方法有 JoinPoint 参数

(3) [掌握]@AfterReturning 后置通知-注解有 returning 属性

(4) [掌握]@Around 环绕通知-增强方法有 ProceedingJoinPoint 参数

(5) [了解]@AfterThrowing 异常通知-注解中有 throwing 属 性

(6) [了解]@After 最终通知

(7) @Pointcut 定义切入点

总结


前言

本文主要讲解spring当中的AOP切面编程介绍以及相关案例的使用,以及aspectj基于注解的AOP实现。

一 AOP介绍

1.0 不使用切面编程额开发方式

先定义好接口与一个实现类,该实现类中除了要实现接口中的方法外,还要再写两个非业务方法。非业务方法也称为交叉业务逻辑:

  • doTransaction():用于事务处理

  • doLog():用于日志处理

然后,再使接口方法调用它们。接口方法也称为主业务逻辑。

接口:

项目 aop_leadin2

当然,也可以有另一种解决方案:将这些交叉业务逻辑代码放到专门的工 具类或处理类中,由主业务逻辑调用。

 

1.1 AOP简介

AOP (Aspect Orient Programming),直译过来就是 面向切面编程,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。

面向切面编程,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术,如下图所示:

AOP可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离,比如Spring的事务,通过事务的注解配置,Spring会自动在业务方法中开启、提交业务,并且在业务处理失败时,执行相应的回滚策略。

1.2 AOP的作用

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

主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性。

简单的说,AOP 的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。

变成切面编程,主体的代码不会动。

 1.3 两种代理

AOP的底层,就是采用动态代理的方式实现的。采用了两种代理:JDK动态代理【主要了解】、CGLIB动态代理。

  • JDK动态代理:使用Proxy,Method,InvocationHandler【类】创建代理对象;要求目标类必须实现接口。
  • CGLIB动态代理:它是一个第三方的工具库,创建代理对象的原理,是通过继承目标类,创建子类,子类去重写方法,实现增强。子类就是代理对象;要求目标类不能是final【最终类】的,方法也不能是final的,可以不实现接口。【子父类的关系】

AOP为 Aspect Oriented Programming的缩写,意为:面向切面编程,可通过运行期动态代理实现程序功能的统一维护的一种技术。AOP是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP 容器的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、事务、日志、缓存等。

若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混杂不清。

例如,转账,在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事务等交叉业务逻辑,而这些业务逻辑与主业务逻辑间并无直接关系。但,它们的代码量所占比重能达到总代码量的一半甚至还多。它们的存在,不仅产生了大量的“冗余"代码,还大大干扰了主业务逻辑---转账。 

这些可以使用切面来实现

1.4 面向切面编程的好处

1.减少重复

2. 专注业务

 注意:面向切面编程只是面向对象编程的一种补充,

使用AOP减少重复代码,专注业务实现。

 

 1.5 AOP编程术语(掌握)

1)切面(Aspect)

切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面是通知(Advice)。实际就是对主业务逻辑的一种增强

2)连接点(JoinPoint)

连接点指可以被切面织入的具体方法。通常业务接口中的方法均为连接点。 

3)切入点(Pointcut)

切入点【切入的位置,真正实现切入的地方】指声明的一个或多个连接点的集合。通过切入点指定一组方法。被标记为final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的

4)目标对象(Target)

目标对象指将要被增强的对象。即包含主业务逻辑的类的对象。上例中的StudentServicelmpl的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然,不被增强,也就无所谓目标不目标了。

5)通知(Advice)

通知表示切面的执行时间,Advice也叫增强。上例中的 MyInvocationHandler就可以理解为是一种通知。换个角度来说,通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。 

切入点定义切入的位置,通知定义切入的时间。

 1.6 AspectJ对AOP的实现(掌握) 

对于AOP这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向切面编程。然而,Aspect]也实现了AOP的功能,且其实现方式更为简捷,使用更为方便,而且还支持注解式开发。所以,Spring 又将Aspect的对于AOP的实现也引入到了自己的框架中

在Spring 中使用AOP开发时,一般使用Aspect的实现方式。

1.6.0 AspectJ简介

Aspect是一个优秀面向切面的框架,它扩展了Java语言,提供了强大的切面实现。

官网地址:The AspectJ Project | The Eclipse Foundation

AspetJ是 Eclipse的开源项目,官网介绍如下: 

a seamless aspect-oriented extension to the Javatm programming language(一种基于 Java 平台的面向切面编程的语言)

Java platform compatible(兼容 Java 平台,可以无缝扩展)

easy to learn and use(易学易用)

1.6.1 AspectJ 的通知类型(理解)

AspectJ 中常用的通知有五种类型:

(1)前置通知

(2)后置通知【方法执行完成之后执行,方法异常就会执行不到】

(3)环绕通知【前后都执行】

(4)异常通知【发生异常的时候通知】

(5)最终通知【不论发生不发生异常都执行】

1.6.2 AspectJ 的切入点表达式(掌握)

AspectJ 定义了专门的表达式用于指定切入点。表达式的原型是:

execution(modifiers-pattern? ret-type-pattern 
declaring-type-pattern?namepattern(param-pattern) throws-pattern?) 

解释:

  • modifiers-pattern] 访问权限类型
  • ret-type-pattern 返回值类型
  • declaring-type-pattern 包名类名
  • name-pattern(param-pattern) 方法名(参数类型和参数个数)
  • throws-pattern 抛出异常类型
  • ?表示可选的部分

以上表达式共 4 个部分。

execution(访问权限 方法返回值 方法声明(参数) 异常类型)

切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表 达式中明显就是方法的签名。注意,表达式中黑色文字表示可省略部分,各部 分间用空格分开。在其中可以使用以下符号:

举例:

  • execution(public * *(..)) 指定切入点为:任意公共方法。
  • execution(* set*(..)) 指定切入点为:任何一个以“set”开始的方法。
  • execution(* com.xyz.service..(..)) 指定切入点为:定义在 service 包里的任意类的任意方法。
  • execution(* com.xyz.service...(..)) 指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“..”出现 在类名中时,后面必须跟“*”,表示包、子包下的所有类。
  • execution(* ..service..*(..)) 指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点
  • execution(* .service..*(..)) 指定只有一级包下的 serivce 子包下所有类(接口)中所有方法为切入点
  • execution(* .ISomeService.(..)) 指定只有一级包下的 ISomeSerivce 接口中所有方法为切入点
  • execution(* ..ISomeService.(..)) 指定所有包下的 ISomeSerivce 接口中所有方法为切入点
  • execution(* com.xyz.service.IAccountService.*(..)) 指定切入点为:IAccountService 接口中的任意方法。
  • execution(* com.xyz.service.IAccountService+.*(..)) 指定切入点为:IAccountService 若为接口,则为接口中的任意方法及其所有 实现类中的任意方法;若为类,则为该类及其子类中的任意方法。
  • execution(* joke(String,int))) 指定切入点为:所有的 joke(String,int)方法,且 joke()方法的第一个参数是 String,第二个参数是 int。如果方法中的参数类型是 java.lang 包下的类,可 以直接使用类名,否则必须使用全限定类名,如 joke( java.util.List, int)。
  • execution(* joke(String,*))) 指定切入点为:所有的 joke()方法,该方法第一个参数为 String,第二个参数 可以是任意类型,如 joke(String s1,String s2)和 joke(String s1,double d2) 都是,但 joke(String s1,double d2,String s3)不是。
  • execution(* joke(String,..))) 指定切入点为:所有的 joke()方法,该方法第一个参数为 String,后面可以有 任意个参数且参数类型不限,如 joke(String s1)、joke(String s1,String s2)和 joke(String s1,double d2,String s3)都是。
  • execution(* joke(Object)) 指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类 型。joke(Object ob)是,但,joke(String s)与 joke(User u)均不是。
  • execution(* joke(Object+))) 指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型 或该类的子类。不仅 joke(Object ob)是,joke(String s)和 joke(User u)也 是。

二 不使用AOP的开发方式的案例讲解

2.1 加入Maven项目spring-aop-leadin1

添加的依赖如下:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.26</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.26</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

 加入依赖之后需要更新一下。

 2.2 创建接口SomeService

 输入接口的代码:

package com.ambow.service;

public interface SomeService {
    //实现业务方法
    void doSome();
    //实现其他的方法
    void doOther();
}

 2.3 编辑接口的实现类SomeServiceImpl

在IDEA里面的快捷键创建接口的实现类

alt+enter输入实现类的名称以及实现类所在的包 

package com.ambow.service.impl;

import com.ambow.service.SomeService;
import com.ambow.service.util.ServiceUtil;

import java.util.Date;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {
        //不加入aop时如果要在开始之前加入---需要每次都要修改硬编码
        //System.out.println("-------开始日志"+ new Date()+"-----");
        System.out.println("开始日志"+ new Date());       
        System.out.println("======doSome方法=======");
        System.out.println("结束日志"+ new Date());
        
    }

    @Override
    public void doOther() {
        System.out.println("开始日志"+ new Date());
        System.out.println("======doOther方法=======");
        System.out.println("结束日志"+ new Date());
    }
}

2.3.1 优化实现类的方案一

直接在代码里面加入方法的优化方法

package com.ambow.service.impl;

import com.ambow.service.SomeService;
import com.ambow.service.util.ServiceUtil;

import java.util.Date;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {
        //优化一下,第一种方法
        beginLog();
        System.out.println("======doSome方法=======");
        endLog();        
    }

    @Override
    public void doOther() {
        //优化一下,第一种方法
        beginLog();
        System.out.println("======doOther方法=======");
        //优化一下,第一种方法
        endLog();
    }
    //写两个日志开始于结束的方法,直接调用方法
    public void beginLog(){
        System.out.println("开始日志"+ new Date());
    }

    public void endLog(){
        System.out.println("结束日志"+ new Date());
    }
}

2.3.2 优化实现类的方案二

在项目里面编写一个ServiceUtil类,将两个方法放在这个类里面。

package com.ambow.service.util;

import java.util.Date;

public class ServiceUtil {
    public static void beginLog(){
        System.out.println("开始日志"+ new Date());
    }

    public static void endLog(){
        System.out.println("结束日志"+ new Date());
    }
}

修改原来接口实现类的代码

package com.ambow.service.impl;

import com.ambow.service.SomeService;
import com.ambow.service.util.ServiceUtil;

import java.util.Date;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {
        //优化的第二种方法
        ServiceUtil.beginLog();
        System.out.println("======doSome方法=======");    
        //优化的第二种方法
        ServiceUtil.endLog();
    }

    @Override
    public void doOther() {
        //优化的第一种方法        
        ServiceUtil.beginLog();
        System.out.println("======doOther方法=======");
        //优化的第二种方法
        ServiceUtil.endLog();
    }
}

2.4 编辑测试类 

package com.ambow.test;

import com.ambow.service.SomeService;
import com.ambow.service.impl.SomeServiceImpl;
import org.junit.Test;

public class AopLeadinTest {
    @Test
    public void test01(){
        SomeService someService = new SomeServiceImpl();
        someService.doSome();
    }
}

这种传统方式的维护较为困难。 

 三 使用JDK动态代理开发AOP项目

3.1 创建Maven项目【此处使用的是JDK动态代理

 将原来的spring-aop-leadin1项目里面的接口和util拿过来,编辑一个测试类

3.2 加入一个 handler文件夹原来存放JDK代理

加入一个新的类——handler.MylnvocationHandler

 

 使得这个类继承InvocationHandler类

 接口实现类的代码段:

package com.ambow.handler;

import com.ambow.util.ServiceUtil;
import org.omg.DynamicAny.DynAnyPackage.InvalidValueHelper;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//JDK动态代理的代理对象InvalidValueHelper

public class MylnvocationHandler implements InvocationHandler {
    private Object target;//此处为目标对象【业务层service】
    //加入target的构造方法或者set方法都可以


    public MylnvocationHandler(Object target) {
        this.target = target;
    }

//    public void setTarget(Object target) {
//        this.target = target;
//    }

    //Method是反射【指的对应的目标对象方法】,需要加入目标对象参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //原来的代码实现是怎么样还是怎么样,不改变原来的代码,只是在前后加入代理
        ServiceUtil.beginLog();//前置功能模块

        //可以理解为Method将doSome()方法封装为一个对象,使用invoke唤醒对象
        //相当于原来的target.doSome()【原来的功能】
        Object result = method.invoke(target, args);

        ServiceUtil.endLog();//后置功能模块
        return null;
    }
}

接口的定义与前面的相同。

接口实现类SomeServiceImpl的代码:

package com.ambow.service.impl;

import com.ambow.service.SomeService;
import com.ambow.util.ServiceUtil;
//原始的功能代码并未修改
//相当于将业务代码与日志代码分离开来,维护较为方便
public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {
        System.out.println("======doSome方法=======");
    }

    @Override
    public void doOther() {
        System.out.println("======doOther方法=======");
    }
}

3.3 编辑一个测试类二

package com.ambow.test;

import com.ambow.handler.MylnvocationHandler;
import com.ambow.service.SomeService;
import com.ambow.service.impl.SomeServiceImpl;
import org.junit.Test;

import java.lang.reflect.Proxy;

public class JDKProxyTest {
    @Test
    public void test01(){
        SomeService someService = new SomeServiceImpl();
        someService.doSome();
    }

    //测试JDK动态代理
    //效果:原来的代码不改动,实现功能的增强
    @Test
    public void test02(){
        //1.创建目标对象
        SomeService target = new SomeServiceImpl();
        //2.创建handler,将target传进来
        MylnvocationHandler handler = new MylnvocationHandler(target);
        //3.创建代理对象
        //此处的代理对象应该与SomeService相同,是这个SomeService类的实现类
        //Proxy代理类的(newProxyInstance)方法创建新的代理实例
        //target.getClass().getClassLoader()获得类加载器
        //target.getClass().getInterfaces()目标对象实现的接口
        //最后将handler传进来
        SomeService proxy = (SomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), handler);
        //4.跳过代理对象来实现类的方法,实现功能
        proxy.doSome();
    }
}

 四 使用spring-aop-aspectj的框架来实现AOP编程

4.1 创建Maven项目

项目架构:

4.2 导入依赖 

(1)Maven依赖 

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.26</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.26</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

(2) 引入 AOP 约束

在 AspectJ 实现 AOP 时,要引入 AOP 的约束。配置文件中使用的 AOP 约束中的标签,均是 AspectJ 框架使用的,而非 Spring 框架本身在实现 AOP 时使用的。

AspectJ 对于 AOP 的实现有注解和配置文件两种方式,常用是注解方式。

4.3  AspectJ 基于注解的 AOP 实现(掌握)

AspectJ 提供了以注解方式对于 AOP 的实现。

(1) 实现步骤

A、 Step1:定义业务接口与实现类

或者将前面jdk-proxy里面的service拿过来。 

B、Step2:定义切面类

类中定义了若干普通方法,将作为不同的通知方法,用来增强功能。

创建一个aspect的MyAspect类

package com.ambow.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

//定义切面类:功能增强
//加入注解,说明是一个切面
@Aspect
public class MyAspect {
    //引入Before前置通知
    //属性:value切入点表达式[切入到目标类的那个方法上去],表达切面的执行位置
    //execution(参数类型  执行的包名称.类名称.类的方法(里面的参数可以任意))
    //位置:在方法的定义之前
    //
    @Before(value = "execution(* com.ambow.service.impl.SomeServiceImpl.doSome(..))")
    public void myBefore(){
        System.out.println("前置通知:在目标方法之前执行,例如:日志");
    }
}
C、Step3:声明目标对象切面类对象

此处为配置文件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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--声明目标类对象-->
    <bean id="someService" class="com.ambow.service.impl.SomeServiceImpl"/>

    <!--声明切面类对象-->
    <bean id="myAspect" class="com.ambow.aspect.MyAspect"/>

    <!--声明自动代理生成器 -> 创建代理 -->
    <aop:aspectj-autoproxy/>
</beans>
D、 Step4:注册 AspectJ 的自动代理

此处做一声明

原来的方式需要我们自己写

现在直接自己自动代理生成 

在定义好切面 Aspect 后,需要通知 Spring 容器,让容器生成“目标类+ 切面”的代理对象。这个代理是由容器自动生成的。只需要在 Spring 配置文 件中注册一个基于 aspectj 的自动代理生成器,其就会自动扫描到@Aspect 注 解,并按通知类型与切入点,将其织入,并生成代理。

<aop:aspectj-autoproxy />的底层是由 AnnotationAwareAspectJAutoProxyCreator 【注释感知 AspectJ 自动代理创建器】实现的。从其类名就可看出, 是基于 AspectJ 的注解适配自动代理生成器。

其工作原理是,通过扫描找到@Aspect 定义的切面类,再由切面类根据切入点找到目标类的目标方法,再由通知类型找到切入的时间点。

E、 Step5:测试类中使用目标对象的 id

 编辑测试类

package com.ambow.test;

import com.ambow.service.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AspectjTest {
    @Test
    public void test01(){
        //从容器里面获取对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //创建接口对象
        SomeService someService = (SomeService) context.getBean("someService");
        //接口调用方法
        someService.doSome();
    }
}

加入打印的类,接着运行既可以看到调用的类

(2) [掌握]@Before 前置通知-方法有 JoinPoint 参数

在目标方法执行之前执行。被注解为前置通知的方法,可以包含一个 JoinPoint 类型参数。该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、目标对象等。

不光前置通知的方法,可以包含一个 JoinPoint 类型参数,所有的通知方法均可包含该参数。

 此处修改一下接口的声明

package com.ambow.service;

public interface SomeService {
    void doSome(String name,int age);
    void doOther();
}

接口类的修改:

package com.ambow.service.impl;

import com.ambow.service.SomeService;
//原始的功能代码并未修改
//相当于将业务代码与日志代码分离开来,维护较为方便
public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name,int age) {
        //此处打印输出一下具体的参数
        System.out.println("======doSome方法=======" + name + ":" + age);
    }

    @Override
    public void doOther() {
        System.out.println("======doOther方法=======");
    }
}

测试类修改:

@Test
    public void test02(){
        //从容器里面获取对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //创建接口对象
        SomeService someService = (SomeService) context.getBean("someService");
        //打印一下获取的类
        System.out.println(someService.getClass());
        //接口调用方法,此时需要传递参数
        someService.doSome("张三",18);
    }

package com.ambow.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

//定义切面类:功能增强
//加入注解,说明是一个切面
@Aspect
public class MyAspect {
    @Before(value = "execution(* com.ambow.service.impl.SomeServiceImpl.doSome(..))")
    // 1、JoinPoint: 表示连接点的方法
    public void myBefore(JoinPoint jp){
        System.out.println("连接点方法的定义:"+ jp.getSignature());
        System.out.println("连接点方法的参数个数:"+ jp.getArgs().length);

        Object[] args= jp.getArgs();
        for (Object arg : args) {
            System.out.println(arg);
        }
        System.out.println("前置通知:在目标方法之前执行,例如:日志");
    }
}

再次运行测试 

(3) [掌握]@AfterReturning 后置通知-注解有 returning 属性

在目标方法执行之后执行。由于是目标方法之后执行,所以可以获取到目标方法的返回值。该注解的 returning 属性就是用于指定接收方法返回值的变量名的。所以,被注解为后置通知的方法,除了可以包含 JoinPoint 参数外, 还可以包含用于接收返回值的变量。该变量最好为 Object 类型,因为目标方法的返回值可能是任何类型。

接口增加方法:

 重写的接口方法:【此时的接口有返回值】

package com.ambow.service;

public interface SomeService {
    void doSome(String name,int age);
    //此处就会有返回值类型
    String doOther(String name,int age);
}

实现方法:

 重写的接口实现类的方法:【此处需要修改原来的接口返回值类型并且给接口一个返回的参数】

@Override
    public String doOther(String name,int age) {
        System.out.println("======doOther方法======="+ name + ":" + age);
        return "abcd";
    }

定义切面:

 切面新增的后置通知代码:

//后置通知,返回还要加入
    @AfterReturning(value = "execution(* com.ambow.service.impl.SomeServiceImpl.doOther(..))",returning = "result")
    public void myAfterReturning(Object result){
        //修改目标方法的执行结果
        if (result !=null){
            //强制转换为String
            String s = (String) result;
            //转换为大写
            result = s.toUpperCase();
        }
        System.out.println("后置通知:在目标方法之后执行,例如:执行事务处理(切面)" +result);
    }

编写测试类test03:

@Test
    public void test03(){
        //从容器里面获取对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //创建接口对象
        SomeService someService = (SomeService) context.getBean("someService");
        //打印一下获取的类
        System.out.println(someService.getClass());
        //接口调用方法,此时需要传递参数
        someService.doOther("李四",28);
    }

 执行结果:

(4) [掌握]@Around 环绕通知-增强方法有 ProceedingJoinPoint 参数

在目标方法执行之前之后执行。被注解为环绕增强的方法要有返回值, Object 类型。并且方法可以包含一个 ProceedingJoinPoint 类型的参数。接口 ProceedingJoinPoint 其有一个 proceed()方法,用于执行目标方法。若目标方法有返回值,则该方法的返回值就是目标方法的返回值。最后,环绕增强 方法将其返回值返回。该增强方法实际是拦截了目标方法的执行。

接口增加方法:

package com.ambow.service;

public interface SomeService {
    void doSome(String name,int age);
    //此处就会有返回值类型
    String doOther(String name,int age);
    String doFirst(String name,int age);
}

 接口方法的实现:

 

 接口实现类的新增部分:

@Override
    public String doFirst(String name, int age) {
        System.out.println("======doFirst方法======="+ name + ":" + age);
        return "doFirst";
    }

定义切面:

 切面新增的方法:

//环绕通知——>环绕通知=前置+目标方法执行+后置通知
    @Around(value = "execution(* com.ambow.service.impl.SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        //增强功能
        System.out.println("环绕通知:在目标方法之前执行,例如:输出日志");
        //,proceed方法就是用于启动目标方法执行
        Object obj = pjp.proceed();//调用目标方法
        //增强的功能
        System.out.println("环绕通知:在目标方法之后执行,例如:处理事务");
        return obj;
    }
@Test
    public void test04(){
        //1.获取到Spring的容器
        //使用技巧:连续按住shift两次就可以看到类,ctrl+h可以查看ApplicationContext接口
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.从容器当中取出对象
        //创建接口对象
        SomeService someService = (SomeService) ctx.getBean("someService");
        //接口调用方法,此时需要传递参数
        someService.doFirst("王五",22);
    }

  

(5) [了解]@AfterThrowing 异常通知-注解中有 throwing 属 性

在目标方法抛出异常后执行。该注解的 throwing 属性用于指定所发生的异常类对象。当然,被注解为异常通知的方法可以包含一个参数 Throwable,参数名称为 throwing 指定的名称,表示发生的异常对象。

增加业务方法:

package com.ambow.service;

public interface SomeService {
    void doSome(String name,int age);
    //此处就会有返回值类型
    String doOther(String name,int age);
    String doFirst(String name,int age);
    void doSecond();
}

方法实现:

@Override
    public void doSecond() {
        System.out.println("======doSecond方法========" + (10/0));
    }

此处人为制造异常

定义切面:

 异常通知的方法:

//异常通知
    @AfterThrowing(value = "execution(* com.ambow.service.impl.SomeServiceImpl.doSecond(..))",throwing = "ex")
    public void myAfterThrowing(Throwable ex){
        //把异常发生的时间,位置,原因记录到数据库,日志文件等等,
        //可以在异常发生时,把异常信息通过短信,邮件发送给开发人员。
        System.out.println("异常通知:在目标方法抛出异常的时候执行,异常原因:" + ex.getMessage());
    }
 @Test
    public void test05(){
        //1.获取到Spring的容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.从容器当中取出对象
        //创建接口对象
        SomeService someService = (SomeService) ctx.getBean("someService");
        //接口调用方法,此时需要传递参数
        someService.doSecond();
    }

 此时如果前面的(10/0)换成(10/2)则不会在处理异常

(6) [了解]@After 最终通知

无论目标方法是否抛出异常,该增强均会被执行。

增加方法:

package com.ambow.service;

public interface SomeService {
    void doSome(String name,int age);
    //此处就会有返回值类型
    String doOther(String name,int age);
    String doFirst(String name,int age);
    void doSecond();
    void doThird();
}

方法实现:

@Override
    public void doThird() {
        System.out.println("=======doThird方法=======" + (10/0));
    }

定义切面:

//最终通知
    @After(value = "execution(* com.ambow.service.impl.SomeServiceImpl.doThird(..))")
    public void myAfter(){
        System.out.println("最终通知:总是会被执行的方法");
    }
@Test
    public void test06(){
        //1.获取到Spring的容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.从容器当中取出对象
        //创建接口对象
        SomeService someService = (SomeService) ctx.getBean("someService");
        //接口调用方法,此时需要传递参数
        someService.doThird();
    }

  

(7) @Pointcut 定义切入点

当较多的通知增强方法使用相同的 execution 切入点表达式时,编写、维护均较为麻烦。AspectJ 提供了@Pointcut 注解,用于定义 execution 切入点表达式。

其用法是,将@Pointcut 注解在一个方法之上,以后所有的 execution 的 value 属性值均可使用该方法名作为切入点。代表的就是@Pointcut 定义的切 入点。这个使用@Pointcut 注解的方法一般使用 private 的标识方法,即没有实际作用的方法。

//相当于给切入点表达式,起一个别名
    @Pointcut(value = "execution(* com.ambow.service.impl.SomeServiceImpl.*(..))")
    public void myPointcut() {
    }

修改环绕通知:

//环绕通知——>环绕通知=前置+目标方法执行+后置通知
    @Around(value = "myPointcut()")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        //增强功能
        System.out.println("环绕通知:在目标方法之前执行,例如:输出日志");
        //,proceed方法就是用于启动目标方法执行
        Object obj = pjp.proceed();//调用目标方法
        //增强的功能
        System.out.println("环绕通知:在目标方法之后执行,例如:处理事务");
        return obj;
    }

 

 

总结

以上就是今天的内容~

欢迎大家点赞👍,收藏⭐,转发🚀,
如有问题、建议,请您在评论区留言💬哦。

最后:转载请注明出处!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1. 简介 1.1. 概览 1.2. 使用场景 2. Spring 2.0 的新特性 2.1. 简介 2.2. 控制反转(IoC)容器 2.2.1. 更简单的XML配置 2.2.2. 新的bean作用域 2.2.3. 可扩展的XML编写 2.3. 面向切面编程(AOP) 2.3.1. 更加简单的AOP XML配置 2.3.2. 对@AspectJ 切面的支持 2.4. 中间层 2.4.1. 在XML里更为简单的声明性事务配置 2.4.2. JPA 2.4.3. 异步的JMS 2.4.4. JDBC 2.5. Web层 2.5.1. Spring MVC的表单标签库 2.5.2. Spring MVC合理的默认值 2.5.3. Portlet 框架 2.6. 其他特性 2.6.1. 动态语言支持 2.6.2. JMX 2.6 .3. 任务规划 2.6.4. 对Java 5(Tiger)的支持 2.7. 移植到Spring 2.0 2.7.1. 一些变化 2.7.1.1. Jar包 2.7.1.2. XML配置 2.7.1.3. Deprecated的类和方法 2.7.1.4. Apache OJB 2.7.1.5. iBatis 2.8. 更新的样例应用 2.9. 改进的文档 I. 核心技术 3. 控制反转容器 3.1. 简介 3.2. 容器和bean的基本原理 3.2.1. 容器 3.2.1.1. 配置元数据 3.2.2. 实例化容器 3.2.2.1. 组成基于XML配置元数据 3.2.3. 多种bean 3.2.3.1. 命名bean 3.2.3.2. 实例化bean 3.2.4. 使用容器 3.3. 依赖 3.3.1. 注入依赖 3.3.1.1. Setter注入 3.3.1.2. 构造器注入 3.3.1.3. 一些例子 3.3.2. 构造器参数的解析 3.3.2.1. 构造器参数类型匹配 3.3.2.2. 构造器参数的索引 3.3.3. bean属性及构造器参数详解 3.3.3.1. 直接量(基本类型、Strings类型等。) 3.3.3.2. 引用其它的bean(协作者) 3.3.3.3. 内部bean 3.3.3.4. 集合 3.3.3.5. Nulls 3.3.3.6. XML-based configuration metadata shortcuts 3.3.3.7. 组合属性名称 3.3.4. 使用depends-on 3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.6.1. 设置Bean使自动装配失效 3.3.7. 依赖检查 3.3.8. 方法注入 3.3.8.1. Lookup方法注入 3.3.8.2. 自定义方法的替代方案 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.3.1. 初始化web配置 3.4.3.2. Request作用域 3.4.3.3. Session作用域 3.4.3.4. global session作用域 3.4.3.5. 作用域bean与依赖 3.4.4. 自定义作用域 3.5. 定制bean特性 3.5.1. Lifecycle接口 3.5.1.1. 初始化回调 3.5.1.2. 析构回调 3.5.2. 了解自己 3.5.2.1. BeanFactoryAware 3.5.2.2. BeanNameAware 3.6. bean定义的继承 3.7. 容器扩展点 3.7.1. 用BeanPostProcessor定制bean 3.7.1.1. 使用BeanPostProcessor的Hello World示例 3.7.1.2. RequiredAnnotationBeanPostProcessor示例 3.7.2. 用BeanFactoryPostProcessor定制配置元数据 3.7.2.1. PropertyPlaceholderConfigurer示例 3.7.2.2. PropertyOverrideConfigurer示例 3.7.3. 使用FactoryBean定制实例化逻辑 3.8. ApplicationContext 3.8.1. 利用MessageSource实现国际化 3.8.2. 事件 3.8.3. 底层资源的访问 3.8.4. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的singleton 3.9.1. 使用Singleton-helper类 4. 资源 4.1. 简介 4.2. Resource 接口 4.3. 内置 Resource 实现 4.3.1. UrlResource 4.3.2. ClassPathResource 4.3.3. FileSystemResource 4.3.4. ServletContextResource 4.3.5. InputStreamResource 4.3.6. ByteArrayResource 4.4. ResourceLoader 4.5. ResourceLoaderAware 接口 4.6. 把Resource作为属性来配置 4.7. Application context 和Resource 路径 4.7.1. 构造application context 4.7.1.1. 创建 ClassPathXmlApplicationContext 实例 - 简介 4.7.2. Application context构造器中资源路径的通配符 4.7.2.1. Ant风格的pattern 4.7.2.2. classpath*: 前缀 4.7.2.3. 其他关于通配符的说明 4.7.3. FileSystemResource 提示 5. 校验,数据绑定,BeanWrapper,与属性编辑器 5.1. 简介 5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 5.4.2.1. 注册用户自定义的PropertyEditor 6. 使用Spring进行面向切面编程(AOP) 6.1. 简介 6.1.1. AOP概念 6.1.2. Spring AOP的功能和目标 6.1.3. SpringAOP代理 6.2. @AspectJ支持 6.2.1. 启用@AspectJ支持 6.2.2. 声明一个切面 6.2.3. 声明一个切入点(pointcut) 6.2.3.1. 切入点指定者的支持 6.2.3.2. 合并切入点表达式 6.2.3.3. 共享常见的切入点(pointcut)定义 6.2.3.4. 示例 6.2.4. 声明通知 6.2.4.1. 前置通知(Before advice) 6.2.4.2. 返回后通知(After returning advice) 6.2.4.3. 抛出后通知(After throwing advice) 6.2.4.4. 后通知(After (finally) advice) 6.2.4.5. 环绕通知(Around Advice) 6.2.4.6. 通知参数(Advice parameters) 6.2.4.7. 通知(Advice)顺序 6.2.5. 引入(Introductions) 6.2.6. 切面实例化模型 6.2.7. 例子 6.3. Schema-based AOP support 6.3.1. 声明一个切面 6.3.2. 声明一个切入点 6.3.3. 声明通知 6.3.3.1. 通知(Advice) 6.3.3.2. 返回后通知(After returning advice) 6.3.3.3. 抛出异常后通知(After throwing advice) 6.3.3.4. 后通知(After (finally) advice) 6.3.3.5. 通知 6.3.3.6. 通知参数 6.3.3.7. 通知顺序 6.3.4. 引入 6.3.5. 切面实例化模型 6.3.6. Advisors 6.3.7. 例子 6.4. AOP声明风格的选择 6.4.1. Spring AOP还是完全用AspectJ? 6.4.2. Spring AOP中使用@AspectJ还是XML? 6.5. 混合切面类型 6.6. 代理机制 6.7. 编程方式创建@AspectJ代理 6.8. 在Spring应用中使用AspectJ 6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.1.1. @Configurable object的单元测试 6.8.1.2. 多application context情况下的处理 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 7.2.3. AspectJ切入点表达式 7.2.4. 便利的切入点实现 7.2.4.1. 静态切入点 7.2.4.2. 动态切入点 7.2.5. 切入点的基类 7.2.6. 自定义切入点 7.3. Spring的通知API 7.3.1. 通知的生命周期 7.3.2. Spring里的通知类型 7.3.2.1. 拦截around通知 7.3.2.2. 前置通知 7.3.2.3. 异常通知 7.3.2.4. 后置通知 7.3.2.5. 引入通知 7.4. Spring里的advisor(Advisor) API 7.5. 使用ProxyFactoryBean创建AOP代理 7.5.1. 基础 7.5.2. JavaBean属性 7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”advisor 7.6. 简化代理定义 7.7. 使用ProxyFactory通过编程创建AOP代理 7.8. 操作被通知对象 7.9. 使用“自动代理(autoproxy)”功能 7.9.1. 自动代理bean定义 7.9.1.1. BeanNameAutoProxyCreator 7.9.1.2. DefaultAdvisorAutoProxyCreator 7.9.1.3. AbstractAdvisorAutoProxyCreator 7.9.2. 使用元数据驱动的自动代理 7.10. 使用TargetSources 7.10.1. 热交换目标源 7.10.2. 池化目标源 7.10.3. 原型目标源 7.10.4. ThreadLocal目标源 7.11. 定义新的通知类型 7.12. 更多资源 8. 测试 8.1. 简介 8.2. 单元测试 8.3. 集成测试 8.3.1. Context管理和缓存 8.3.2. 测试fixture的依赖注入 8.3.3. 事务管理 8.3.4. 方便的变量 8.3.5. 示例 8.3.6. 运行集成测试 8.4. 更多资源 II. 中间层数据访问 9. 事务管理 9.1. 简介 9.2. 动机 9.3. 关键抽象 9.4. 使用资源同步的事务 9.4.1. 高层次方案 9.4.2. 低层次方案 9.4.3. TransactionAwareDataSourceProxy 9.5. 声明式事务管理 9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.6.1. @Transactional 有关的设置 9.5.7. 插入事务操作 9.5.8. 结合AspectJ使用 @Transactional 9.6. 编程式事务管理 9.6.1. 使用 TransactionTemplate 9.6.2. 使用 PlatformTransactionManager 9.7. 选择编程式事务管理还是声明式事务管理 9.8. 与特定应用服务器集成 9.8.1. BEA WebLogic 9.8.2. IBM WebSphere 9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1. 简介 11.1.1. Spring JDBC包结构 11.2. 利用JDBC核心类实现JDBC的基本操作和错误处理 11.2.1. JdbcTemplate类 11.2.2. NamedParameterJdbcTemplate类 11.2.3. SimpleJdbcTemplate类 11.2.4. DataSource接口 11.2.5. SQLExceptionTranslator接口 11.2.6. 执行SQL语句 11.2.7. 执行查询 11.2.8. 更新数据库 11.3. 控制数据库连接 11.3.1. DataSourceUtils类 11.3.2. SmartDataSource接口 11.3.3. AbstractDataSource类 11.3.4. SingleConnectionDataSource类 11.3.5. DriverManagerDataSource类 11.3.6. TransactionAwareDataSourceProxy类 11.3.7. DataSourceTransactionManager类 11.4. 用Java对象来表达JDBC操作 11.4.1. SqlQuery类 11.4.2. MappingSqlQuery类 11.4.3. SqlUpdate类 11.4.4. StoredProcedure类 11.4.5. SqlFunction类 12. 使用ORM工具进行数据访问 12.1. 简介 12.2. Hibernate 12.2.1. 资源管理 12.2.2. 在Spring的application context中创建 SessionFactory 12.2.3. HibernateTemplate 12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器中使用Hibernate的注意点 12.3. JDO 12.3.1. 建立PersistenceManagerFactory 12.3.2. JdoTemplate和JdoDaoSupport 12.3.3. 基于原生的JDO API实现DAO 12.3.4. 事务管理 12.3.5. JdoDialect 12.4. Oracle TopLink 12.4.1. SessionFactory 抽象层 12.4.2. TopLinkTemplate 和 TopLinkDaoSupport 12.4.3. 基于原生的TopLink API的DAO实现 12.4.4. 事务管理 12.5. iBATIS SQL Maps 12.5.1. iBATIS 1.x和2.x的概览与区别 12.5.2. iBATIS SQL Maps 1.x 12.5.2.1. 创建SqlMap 12.5.2.2. 使用 SqlMapTemplate 和 SqlMapDaoSupport 12.5.3. iBATIS SQL Maps 2.x 12.5.3.1. 创建SqlMapClient 12.5.3.2. 使用 SqlMapClientTemplate 和 SqlMapClientDaoSupport 12.5.3.3. 基于原生的iBATIS API的DAO实现 12.6. JPA 12.6.1. 在Spring环境中建立JPA 12.6.1.1. LocalEntityManagerFactoryBean 12.6.1.2. LocalContainerEntityManagerFactoryBean 12.6.1.3. 处理多个持久化单元 12.6.2. JpaTemplate 和 JpaDaoSupport 12.6.3. 基于原生的JPA实现DAO 12.6.4. 异常转化 12.6.5. 事务管理 12.6.6. JpaDialect III. Web 13. Web框架 13.1. 介绍 13.1.1. 与其他web框架的集成 13.1.2. Spring Web MVC框架的特点 13.2. DispatcherServlet 13.3. 控制器 13.3.1. AbstractController 和 WebContentGenerator 13.3.2. 其它的简单控制器 13.3.3. MultiActionController 13.3.4. 命令控制器 13.4. 处理器映射(handler mapping) 13.4.1. BeanNameUrlHandlerMapping 13.4.2. SimpleUrlHandlerMapping 13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.5.3.1. RedirectView 13.5.3.2. redirect:前缀 13.5.3.3. forward:前缀 13.6. 本地化解析器 13.6.1. AcceptHeaderLocaleResolver 13.6.2. CookieLocaleResolver 13.6.3. SessionLocaleResolver 13.6.4. LocaleChangeInterceptor 13.7. 使用主题 13.7.1. 简介 13.7.2. 如何定义主题 13.7.3. 主题解析器 13.8. Spring对分段文件上传(multipart file upload)的支持 13.8.1. 介绍 13.8.2. 使用MultipartResolver 13.8.3. 在表单中处理分段文件上传 13.9. 使用Spring的表单标签库 13.9.1. 配置标签库 13.9.2. form标签 13.9.3. input标签 13.9.4. checkbox标签 13.9.5. radiobutton标签 13.9.6. password标签 13.9.7. select标签 13.9.8. option标签 13.9.9. options标签 13.9.10. textarea标签 13.9.11. hidden标签 13.9.12. errors标签 13.10. 处理异常 13.11. 惯例优先原则(convention over configuration) 13.11.1. 对控制器的支持: ControllerClassNameHandlerMapping 13.11.2. 对模型的支持:ModelMap (ModelAndView) 13.11.3. 对视图的支持: RequestToViewNameTranslator 13.12. 其它资源 14. 集成视图技术 14.1. 简介 14.2. JSP和JSTL 14.2.1. 视图解析器 14.2.2. 'Plain-old' JSPs versus JSTL 'Plain-old' JSP与JSTL 14.2.3. 帮助简化开发的额外的标签 14.3. Tiles 14.3.1. 需要的资源 14.3.2. 如何集成Tiles 14.3.2.1. InternalResourceViewResolver 14.3.2.2. ResourceBundleViewResolver 14.4. Velocity和FreeMarker 14.4.1. 需要的资源 14.4.2. Context 配置 14.4.3. 创建模板 14.4.4. 高级配置 14.4.4.1. velocity.properties 14.4.4.2. FreeMarker 14.4.5. 绑定支持和表单处理 14.4.5.1. 用于绑定的宏 14.4.5.2. 简单绑定 14.4.5.3. 表单输入生成宏 14.4.5.4. 重载HTML转码行为并使你的标签符合XHTML 14.5. XSLT 14.5.1. 写在段首 14.5.1.1. Bean 定义 14.5.1.2. 标准MVC控制器代码 14.5.1.3. 把模型数据转化为XML 14.5.1.4. 定义视图属性 14.5.1.5. 文档转换 14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.6.2.1. 文档视图定义 14.6.2.2. Controller 代码 14.6.2.3. Excel视图子类 14.6.2.4. PDF视图子类 14.7. JasperReports 14.7.1. 依赖的资源 14.7.2. 配置 14.7.2.1. 配置ViewResolver 14.7.2.2. 配置View 14.7.2.3. 关于报表文件 14.7.2.4. 使用 JasperReportsMultiFormatView 14.7.3. 构造ModelAndView 14.7.4. 使用子报表 14.7.4.1. 配置子报表文件 14.7.4.2. 配置子报表数据源 14.7.5. 配置Exporter的参数 15. 集成其它Web框架 15.1. 简介 15.2. 通用配置 15.3. JavaServer Faces 15.3.1. DelegatingVariableResolver 15.3.2. FacesContextUtils 15.4. Struts 15.4.1. ContextLoaderPlugin 15.4.1.1. DelegatingRequestProcessor 15.4.1.2. DelegatingActionProxy 15.4.2. ActionSupport 类 15.5. Tapestry 15.5.1. 注入 Spring 托管的 beans 15.5.1.1. 将 Spring Beans 注入到 Tapestry 页面中 15.5.1.2. 组件定义文件 15.5.1.3. 添加抽象访问方法 15.5.1.4. 将 Spring Beans 注入到 Tapestry 页面中 - Tapestry 4.0+ 风格 15.6. WebWork 15.7. 更多资源 16. Portlet MVC框架 16.1. 介绍 16.1.1. 控制器 - MVC中的C 16.1.2. 视图 - MVC中的V 16.1.3. Web作用范围的Bean 16.2. DispatcherPortlet 16.3. ViewRendererServlet 16.4. 控制器 16.4.1. AbstractController和PortletContentGenerator 16.4.2. 其它简单的控制器 16.4.3. Command控制器 16.4.4. PortletWrappingController 16.5. 处理器映射 16.5.1. PortletModeHandlerMapping 16.5.2. ParameterHandlerMapping 16.5.3. PortletModeParameterHandlerMapping 16.5.4. 增加 HandlerInterceptor 16.5.5. HandlerInterceptorAdapter 16.5.6. ParameterMappingInterceptor 16.6. 视图和它们的解析 16.7. Multipart文件上传支持 16.7.1. 使用PortletMultipartResolver 16.7.2. 处理表单里的文件上传 16.8. 异常处理 16.9. Portlet应用的部署 IV. 整合 17. 使用Spring进行远程访问与Web服务 17.1. 简介 17.2. 使用RMI暴露服务 17.2.1. 使用 RmiServiceExporter 暴露服务 17.2.2. 在客户端链接服务 17.3. 使用Hessian或者Burlap通过HTTP远程调用服务 17.3.1. 为Hessian配置DispatcherServlet 17.3.2. 使用HessianServiceExporter暴露你的bean 17.3.3. 客户端连接服务 17.3.4. 使用Burlap 17.3.5. 对通过Hessian或Burlap暴露的服务使用HTTP基础认证 17.4. 使用HTTP调用器暴露服务 17.4.1. 暴露服务对象 17.4.2. 在客户端连接服务 17.5. Web服务 17.5.1. 使用JAXI-RPC暴露服务 17.5.2. 访问Web服务 17.5.3. 注册bean映射 17.5.4. 注册自己的处理方法 17.5.5. 使用XFire来暴露Web服务 17.6. 对远程接口不提供自动探测 17.7. 在选择这些技术时的一些考虑 18. Enterprise Java Bean(EJB)集成 18.1. 简介 18.2. 访问EJB 18.2.1. 概念 18.2.2. 访问本地的无状态Session Bean(SLSB) 18.2.3. 访问远程SLSB 18.3. 使用Spring提供的辅助类实现EJB组件 19. JMS 19.1. 简介 19.2. 使用Spring JMS 19.2.1. JmsTemplate 19.2.2. 连接工厂 19.2.3. (消息)目的地管理 19.2.4. 消息侦听容器 19.2.4.1. SimpleMessageListenerContainer 19.2.4.2. DefaultMessageListenerContainer 19.2.4.3. ServerSessionMessageListenerContainer 19.2.5. 事务管理 19.3. 发送一条消息 19.3.1. 使用消息转换器 19.3.2. SessionCallback 和ProducerCallback 19.4. 接收消息 19.4.1. 同步接收 19.4.2. 异步接收 - 消息驱动的POJOs 19.4.3. SessionAwareMessageListener 接口 19.4.4. MessageListenerAdapter 19.4.5. 事务中的多方参与 20. JMX 20.1. 介绍 20.2. 输出bean到JMX 20.2.1. 创建一个MBeanServer 20.2.2. 复用现有的MBeanServer 20.2.3. MBean的惰性初始化 20.2.4. MBean的自动注册 20.2.5. 控制注册行为 20.3. 控制bean的管理接口 20.3.1. MBeanInfoAssembler 接口 20.3.2. 使用源码级元数据 20.3.3. 使用JDK 5.0注解 20.3.4. 源代码级的元数据类型 20.3.5. 接口AutodetectCapableMBeanInfoAssembler 20.3.6. 用Java接口定义管理接口 20.3.7. 使用MethodNameBasedMBeanInfoAssembler 20.4. 控制bean的 ObjectName 20.4.1. 从Properties中读取ObjectName 20.4.2. 使用 MetadataNamingStrategy 20.5. JSR-160连接器 20.5.1. 服务器端连接器 20.5.2. 客户端连接器 20.5.3. 基于Burlap/Hessian/SOAP的JMX 20.6. 通过代理访问MBeans 20.7. 通知 20.7.1. 为通知注册监听器 20.7.2. 发布通知 20.8. 更多资源 21. JCA CCI 21.1. 介绍 21.2. 配置CCI 21.2.1. 连接器配置 21.2.2. 在Spring中配置ConnectionFactory 21.2.3. 配置CCI连接 21.2.4. 使用一个 CCI 单连接 21.3. 使用Spring的 CCI访问支持 21.3.1. 记录转换 21.3.2. CciTemplate 类 21.3.3. DAO支持 21.3.4. 自动输出记录生成 21.3.5. 总结 21.3.6. 直接使用一个 CCI Connection 接口和Interaction接口 21.3.7. CciTemplate 使用示例 21.4. 建模CCI访问为操作对象 21.4.1. MappingRecordOperation 21.4.2. MappingCommAreaOperation 21.4.3. 自动输出记录生成 21.4.4. 总结 21.4.5. MappingRecordOperation 使用示例 21.4.6. MappingCommAreaOperation 使用示例 21.5. 事务 22. Spring邮件抽象层 22.1. 简介 22.2. Spring邮件抽象结构 22.3. 使用Spring邮件抽象 22.3.1. 可插拔的MailSender实现 22.4. 使用 JavaMail MimeMessageHelper 22.4.1. 创建一条简单的MimeMessage,并且发送出去 22.4.2. 发送附件和嵌入式资源(inline resources) 23. Spring中的定时调度(Scheduling)和线程池(Thread Pooling) 23.1. 简介 23.2. 使用OpenSymphony Quartz 调度器 23.2.1. 使用JobDetailBean 23.2.2. 使用 MethodInvokingJobDetailFactoryBean 23.2.3. 使用triggers和SchedulerFactoryBean来包装任务 23.3. 使用JDK Timer支持类 23.3.1. 创建定制的timers 23.3.2. 使用 MethodInvokingTimerTaskFactoryBean类 23.3.3. 打包:使用TimerFactoryBean来设置任务 23.4. SpringTaskExecutor抽象 23.4.1. TaskExecutor接口 23.4.2. 何时使用TaskExecutor接口 23.4.3. TaskExecutor类型 23.4.4. 使用TaskExecutor接口 24. 动态语言支持 24.1. 介绍 24.2. 第一个例子 24.3. 定义动态语言支持的bean 24.3.1. 公共概念 24.3.1.1. <lang:language/> 元素 24.3.1.2. Refreshable bean 24.3.1.3. 内置动态语言源文件 24.3.1.4. 理解dynamic-language-backed bean context的构造器注入 24.3.2. JRuby beans 24.3.3. Groovy beans 24.3.4. BeanShell beans 24.4. 场景 24.4.1. Spring MVC控制器脚本化 24.4.2. Validator脚本化 24.5. 更多的资源 25. 注解和源代码级的元数据支持 25.1. 简介 25.2. Spring的元数据支持 25.3. 注解 25.3.1. @Required 25.3.2. Spring中的其它@Annotations 25.4. 集成Jakarta Commons Attributes 25.5. 元数据和Spring AOP自动代理 25.5.1. 基本原理 25.5.2. 声明式事务管理 25.5.3. 缓冲 25.5.4. 自定义元数据 25.6. 使用属性来减少MVC web层配置 25.7. 元数据属性的其它用法 25.8. 增加对额外元数据API的支持 A. XML Schema-based configuration A.1. Introduction A.2. XML Schema-based configuration A.2.1. Referencing the schemas A.2.2. The util schema A.2.2.1. <util:constant/> A.2.2.2. <util:property-path/> A.2.2.3. <util:properties/> A.2.2.4. <util:list/> A.2.2.5. <util:map/> A.2.2.6. <util:set/> A.2.3. The jee schema A.2.3.1. <jee:jndi-lookup/> (simple) A.2.3.2. <jee:jndi-lookup/> (with single JNDI environment setting) A.2.3.3. <jee:jndi-lookup/> (with multiple JNDI environment settings) A.2.3.4. <jee:jndi-lookup/> (complex) A.2.3.5. <jee:local-slsb/> (simple) A.2.3.6. <jee:local-slsb/> (complex) A.2.3.7. <jee:remote-slsb/> A.2.4. The lang schema A.2.5. The tx (transaction) schema A.2.6. The aop schema A.2.7. The tool schema A.2.8. The beans schema A.3. Setting up your IDE A.3.1. Setting up Eclipse A.3.2. Setting up IntelliJ IDEA A.3.3. Integration issues A.3.3.1. XML parsing errors in the Resin v.3 application server B. Extensible XML authoring B.1. Introduction B.2. Authoring the schema B.3. Coding a NamespaceHandler B.4. Coding a BeanDefinitionParser B.5. Registering the handler and the schema B.5.1. META-INF/spring.handlers B.5.2. META-INF/spring.schemas C. spring-beans-2.0.dtd D. spring.tld D.1. Introduction D.2. The bind tag D.3. The escapeBody tag D.4. The hasBindErrors tag D.5. The htmlEscape tag D.6. The message tag D.7. The nestedPath tag D.8. The theme tag D.9. The transform tag E. spring-form.tld E.1. Introduction E.2. The checkbox tag E.3. The errors tag E.4. The form tag E.5. The hidden tag E.6. The input tag E.7. The label tag E.8. The option tag E.9. The options tag E.10. The password tag E.11. The radiobutton tag E.12. The select tag E.13. The textarea tag F. Spring 2.0 开发手册中文化项目 F.1. 声明 F.2. 致谢 F.3. 参与人员及任务分配 F.4. Spring 2.0 正式版开发手册翻译说明 F.5. 项目历程 F.5.1. Spring 2.0 RC2 开发手册翻译项目 F.5.2. Spring 2.0 正式版开发手册翻译项目

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张小鱼༒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值