Spring框架之Spring AOP

一、基于注解管理的AOP

1、Spring配置文件

<!-- 配置自动扫描包,自动扫描Bean组件,切面类 -->

<context:component-scan base-package="com.zhoujian.spring.anno,com.zhoujian.spring.test">

<!-- <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>     -->

</context:component-scan>

<!-- 启动@Aspectj支持 -->

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2、切面类

package com.zhoujian.spring.aspect;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.springframework.stereotype.Component;

@Aspect

@Component

/**

* 如何声明一个切面类: 首先是放入IOC容器进行管理, 其次是需要Aspect进行修饰

*

*/

public class AuthAspectClass {

@Before(value = "execution(* com.zhoujian.spring.anno.*.*(..))")

// @Before("execution(* com.zhoujian.spring.test.*.*(..))")

public void before() {

System.out.println("模拟进行权限检查...");

}

@After("execution(* com.zhoujian.spring.anno.*.*(..))")

public void after() {

/**

* after增强处理,不管目标方法是如何结束的,该方法会在目标方法结束之后被织入

* 如果对同一目标方法进行了after和afterReturning增强处理且目标方法正常执行结束,

* 此时会先织入after增强处理,之后才是afterReturning增强处理,

* 如果目标方法非正常结束, 那么只会在目标方法结束之后,织入after增强处理,

* 如果目标方法的非正常结束抛出了异常,伴儿会在目标方法结束之后,先织入after增强处理,

* 之后才会织入afterThrowing增强处理

*/

System.out.println("关闭当前事务...");

}

@AfterReturning(returning = "returnVal", value = "execution(* com.zhoujian.spring.anno.*.*(..))")

public void afterReturning(Object returnVal) {

System.out.println("目标方法的返回值:" + returnVal);

System.out.println("只有目标方法正常执行完成后,才会执行AfterReturning...");

}

@AfterThrowing(throwing="exception",value="execution(void com.zhoujian.spring.anno.HelloImpl.getSub())")

public void afterThrowing(Exception exception){

System.out.println("只有执行com.zhoujian.spring.anno.HelloImpl.getSub() 该方法 ,才会进行增强");

System.out.println("目标方法抛出的异常为: " + exception.getMessage());

System.out.println("模拟Advice进行异常处理...");

}

@Around("execution(public int com.zhoujian.spring.anno.HelloImpl.total(..))")

public Object around(ProceedingJoinPoint joinPoint){

/**

* Around增强处理是一个很强大,但是通常需要在一个线程安全的环境使用(比如在proceed方法调用前后需要共享数据)

*/

Object result = null;

try {

Object[] args = {6,3,"4"};

/**

* 在这里传入一个Object数组,可以替换目标方法中的实参,偷天换日

* 但是,传入参数的个数和类型应该与目标方法保持一致

* 如果个数少于目标方法参数个数或者类型不匹配都会抛出异常

* 如果是 个数多余目标方法参数个数,那么会从数组下标0开始往后取出相同个数作为实参,此时如果取出的数组元素

* 类型与目标方法类型不匹配,那么也会抛出异常

*/

System.out.println(joinPoint.getThis());

System.out.println(joinPoint.getTarget());

result = joinPoint.proceed(args);

} catch (Throwable e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(result);

/**

* return 返回值时  也可以进行目标方法返回值的修改,偷天换日

*/

return result;

}

}

3、业务类

package com.zhoujian.spring.anno;

import org.springframework.stereotype.Component;

@Component

public class HelloImpl implements Hello {

@Override

public void foo() {

System.out.println("执行Hello组件的 foo()方法...");

}

@Override

public int addUser(String name, String pass) {

System.out.println("执行Hello组件的addUser()方法添加用户: " + name);

return 10;

}

public void getSub(){

System.out.println("执行Hello组件的getSub()方法...");

int num = 12;

if(num % 2 == 0){

throw new NullPointerException("假装我是一个空指针异常...");

}

}

}

4、测试方法

@Test

public void beanTest(){

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

HelloImpl he = ac.getBean(HelloImpl.class);

//        System.out.println(he.getClass());

he.foo();

he.addUser("张三", "123456");

he.getSub();

}

5、定义切入点

package com.zhoujian.spring.aspect;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.stereotype.Component;

@Aspect

@Component

public class LogAspectClass {

/**

* 使用  @Pointcut 定义一个切入点,方法返回类型必须是void

* 因为这仅仅只是一个签名形式的方法,为了声明切入点的名称,不需要方法体,所以方法体也为空

* 如果需要在其他的切面类中进行引用时,必须遵循Java的权限访问控制标准,

* 采用类名为前缀: value="LogAspectClass.myPointcut()"

* 或者 pointcut="LogAspectClass.myPointcut()"

*/

@Pointcut("execution(* com.zhoujian.spring.anno.*.*(..))")

public void myPointcut(){}

@Before(value="myPointcut()")

public void beforeLog(){

System.out.println("使用定义好的切入点");

}

}

二、基于XML管理的AOP

1、Spring配置文件

<!-- 切面类 -->

<bean id="logAspectClassWithXML" class="com.zhoujian.spring.aspect.LogAspectClassWithXML"></bean>

<!-- helloImpl 实现了 Hello 接口 -->

<bean id="helloImpl" class="com.zhoujian.spring.anno.HelloImpl"></bean>

<!-- helloImpl2 是一个单实体类,没有继承任何类和 实现任何接口 -->

<bean id="helloImpl2" class="com.zhoujian.spring.anno.HelloImpl2"></bean>

<!-- fordCarChild 继承了FordCar类-->

<bean id="fordCarChild" class="com.zhoujian.spring.anno.FordCarChild"></bean>

<!-- AOP 配置 -->

<aop:config>

<aop:aspect id="logAspect" ref="logAspectClassWithXML" order="1">

<aop:before method="beforeLog" pointcut="execution(* com.zhoujian.spring.anno.*.*(..))"/>

</aop:aspect>

</aop:config>

2、切面类和相关实体类

Hello接口

package com.zhoujian.spring.anno;

public interface Hello {

public void foo();

public int addUser(String name, String pass);

}

Hello实现类 HelloImpl

package com.zhoujian.spring.anno;

public class HelloImpl implements Hello {

@Override

public void foo() {

System.out.println("执行Hello组件的 foo()方法...");

}

@Override

public int addUser(String name, String pass) {

System.out.println("执行Hello组件的addUser()方法添加用户: " + name);

return 10;

}

public void getSub(){

System.out.println("执行Hello组件的getSub()方法...");

int num = 12;

if(num % 2 == 0){

throw new NullPointerException("假装我是一个空指针异常...");

}

}

public int total(int a, int b){

int total = a + b;

return total;

}

}

单实体类 HelloImpl2

package com.zhoujian.spring.anno;

public class HelloImpl2{

public void foo() {

System.out.println("执行Hello组件的 foo()方法...");

}

public int addUser(String name, String pass) {

System.out.println("执行Hello组件的addUser()方法添加用户: " + name);

return 10;

}

public void getSub(){

System.out.println("执行Hello组件的getSub()方法...");

int num = 12;

if(num % 2 == 0){

throw new NullPointerException("假装我是一个空指针异常...");

}

}

public int total(int a, int b){

int total = a + b;

return total;

}

}

切面类 LogAspectClassWithXML

package com.zhoujian.spring.aspect;

import org.apache.catalina.tribes.util.Arrays;

import org.aspectj.lang.JoinPoint;

public class LogAspectClassWithXML {

public void beforeLog(JoinPoint point){

System.out.println("Before:增强的目标方法名为:" + point.getSignature().getName());

System.out.println("Before:增强的目标方法的参数为:" + Arrays.toString(point.getArgs()));

System.out.println("Before:被织入增强的目标对象为:" + point.getTarget());

}

public void after(JoinPoint point) {

/**

* after增强处理,不管目标方法是如何结束的,该方法会在目标方法结束之后被织入

* 如果对同一目标方法进行了after和afterReturning增强处理且目标方法正常执行结束,

* 此时会先织入after增强处理,之后才是afterReturning增强处理,

* 如果目标方法非正常结束, 那么只会在目标方法结束之后,织入after增强处理,

* 如果目标方法的非正常结束抛出了异常,那么会在目标方法结束之后,先织入after增强处理,

* 之后才会织入afterThrowing增强处理

*/

System.out.println("After: 目标方法结束后释放资源...");

System.out.println("After:增强的目标方法名为:" + point.getSignature().getName());

System.out.println("After:增强的目标方法的参数为:" + Arrays.toString(point.getArgs()));

System.out.println("After:被织入增强的目标对象为:" + point.getTarget());

}

public void afterReturning(JoinPoint point, Object returnVal) {

System.out.println("AfterReturning: 获取目标方法的返回值" + returnVal);

System.out.println("AfterReturning:增强的目标方法名为:" + point.getSignature().getName());

System.out.println("AfterReturning:增强的目标方法的参数为:" + Arrays.toString(point.getArgs()));

System.out.println("AfterReturning:被织入增强的目标对象为:" + point.getTarget());

}

public void afterThrowing(JoinPoint point, Exception exception, String name, String age){

System.out.println("AfterThrowing: 获取到目标方法抛出的异常" + exception.getMessage());

System.out.println("AfterThrowing:增强的目标方法名为:" + point.getSignature().getName());

System.out.println("AfterThrowing:增强的目标方法的参数为:" + Arrays.toString(point.getArgs()));

System.out.println("AfterThrowing:被织入增强的目标对象为:" + point.getTarget());

}

}

3、测试类 AspectWithXMLTest

package com.zhoujian.spring.test;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.zhoujian.spring.anno.HelloImpl2;

public class AspectWithXMLTest {

@Test

public void test() {

ApplicationContext ac = new ClassPathXmlApplicationContext("aspectWithXML.xml");

System.out.println(ac.getBean("helloImpl").getClass().getName());

/**

* helloImpl 实体类实现了一个接口,所以其代理类的获取必须使用其实现的接口进行获取,不然会发生类型转换异常

*/

com.zhoujian.spring.anno.Hello hel = (com.zhoujian.spring.anno.Hello) ac.getBean("helloImpl");

hel.foo();

}

public static void main(String[] args) {

ApplicationContext ac = new ClassPathXmlApplicationContext("aspectWithXML.xml");

/**

* 单实体类:即没有继承和实现任何类和接口的实体类, 在获取其代理对象的时候,直接获取就行了

* 即使目标类继承了一个或者多个类,获取时正常获取即可,用其父类进行获取也行

*/

System.out.println(ac.getBean("helloImpl").getClass().getName());

HelloImpl2 hel = (HelloImpl2) ac.getBean("helloImpl2");

hel.foo();

}

}

注:Spring AOP 由 IOC 容器进行生成和管理,当进行IOC容器创建的时候,IOC容器会扫描切入点表达式所包含的所有包中所有类,并为所有类创建代理对象

如果目标类没有实现任何的接口,Spring将会是cglib方式创建代理对象;

如果目标类实现了一个或多个接口或者,那么Spring将会采用JDK动态代理创建代理类(此时代理类的获取必须使用接口类型接收)

使用Spring版本:spring-framework-4.3.10.RELEASE-dist

时间: 2024-10-07 06:33:39

Spring框架之Spring AOP的相关文章

Spring框架:Spring安全

在传统的Web开发中,安全性的代码都是分散在各个模块中的,这样不方便管理,而且有时候可能会漏掉一个地方导致安全漏洞.为了解决这个问题,有人发明了Spring Security.它的作用是将业务逻辑中有关安全的代码全都移动到一个模块中集中管理.本质上是AOP的一个子集. 过滤URL 为了过滤URL,首先要在web.xml中加入一个过滤器.filter-name不能随便填写,因为它和另外一个bean的名称是一样的. <filter> <filter-name>springSecurit

深入浅出,了解 Spring 框架和 Spring Boot 的历史

Spring 框架可以说是 Java 开发人员使用的最流行的应用程序开发框架之一.它目前由大量提供一系列服务的模块组成.包括模块容器,为构建横切关注点提供支持的面向切面编程(AOP),安全框架,数据存取框架,Web 应用框架和用于模块测试提供支持的类.Spring 框架的所有组件都通过依赖注入粘在一起.依赖注入(也称为控制反转)使设计和测试松散耦合的软件模块变得更容易. 多年来 Spring 框架已变得足够成熟.几乎所有 Java 企业应用需要用到的基础组件都可以在 Spring 框架中找到.但

Spring框架学习——Spring的体系结构详解

1.Spring体系结构简介 Spring框架至今已集成了20多个模块,这些模块分布在以下模块中: 核心容器(Core Container) 数据访问/集成(Data Access/Integration)层 Web层 AOP(Aspect Oriented Programming)模块 植入(Instrumentation)模块 消息传输(Messaging) 测试(Test)模块 Spring体系结构如下图: 2.核心容器 Spring的核心容器是其他模块建立的基础,有Spring-core

Spring框架学习-Spring和IOC概述

一:什么是Spring框架? spring是一个分层的javase/EEfull-stack(一站式)轻量级的java开源框架.是为了解决企业开发的复杂性而创建的.框架的主要优势是分层架构,Spring的核心是控制反转(IOC)和面向切面(AOP). 二.学习Spring的好处? 主要就是方便解耦,简化开发 Spring就像一个工厂,可以将所有对象创建和依赖关系维护,都交给Spring管理. AOP编程的支持 Spring提供面向切面编程,可以方便的实现对程序进行权限拦截.运行监控等功能. 声明

一句话概括下spring框架及spring cloud框架主要组件

作为java的屌丝,基本上跟上spring屌丝的步伐,也就跟上了主流技术.spring 顶级项目:Spring IO platform:用于系统部署,是可集成的,构建现代化应用的版本平台,具体来说当你使用maven dependency引入spring jar包时它就在工作了.Spring Boot:旨在简化创建产品级的 Spring 应用和服务,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用微服务功能,可以和spring cloud联合部署.Spring Framework:即通常所

转:一句话概括下spring框架及spring cloud框架主要组件

作为java的屌丝,基本上跟上spring屌丝的步伐,也就跟上了主流技术. spring 顶级项目:Spring IO platform:用于系统部署,是可集成的,构建现代化应用的版本平台,具体来说当你使用maven dependency引入spring jar包时它就在工作了.Spring Boot:旨在简化创建产品级的 Spring 应用和服务,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用微服务功能,可以和spring cloud联合部署.Spring Framework:即通常

Spring框架4:Spring使用注解和XML配置控制反转(IOC)

本系列笔记均是对b站教程https://www.bilibili.com/video/av47952931 的学习笔记,非本人原创 注解配置IOC 注解配置和基于xml的配置功能是一样的,只是配置形式不一样 这里以一个项目为例,项目还是之前的那个 AccountDAOImpl: package com.jiading.dao.impl; import com.jiading.dao.IAccountDAO; import org.springframework.stereotype.Reposi

Spring框架学习05——AOP相关术语详解

1.Spring AOP 的基本概述 AOP(Aspect Oriented Programing)面向切面编程,AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视.事务管理.安全检查.缓存).Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码. 2.AOP的相关术语 在Spring AOP 框架中涉及以下常用术语: 连接点(Joinpoint):是指程序运行中的一些时间点,即那些被拦截到的点,例如方法的调用或异常的抛

面试之Spring框架IOC和AOP的实现原理

IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控.控制权由应用代码中转到了外部容器,控制权的转移是所谓反转. 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系:IoC还有另外一个名字--"依赖注入(Dependency Injection)".从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某