spring面向切面aop拦截器

spring中有很多概念和名词,其中有一些名字不同,但是从功能上来看总感觉是那么的相似,比如过滤器、拦截器、aop等。

过滤器filter、spring mvc拦截器Interceptor 、面向切面编程aop,实际上都具有一定的拦截作用,都是拦截住某一个面,然后进行一定的处理。

在这里主要想着手的是aop,至于他们的比较,我想等三个都一一了解完了再说,因此这里便不做过多的比较。

在我目前的项目实践中,只在一个地方手动显示的使用了aop,那便是日志管理中对部分重要操作的记录。

据我目前所知,aop拦截一般都是用在具体的方法上,或者说是具体的某一类方法,我所用过的实现方式有两种,一种是直接代码声明,一种是在xml文件中配置。

由于我目前实际开发的项目都是使用spring+spring mvc的架构,然后使用maven管理,然后junit测试。因此我自己几乎所有的个人项目也都是采用这些架构和项目管理工具,在这个理解aop的小项目中,自然也是这样,依赖包如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>springTest</groupId>
  <artifactId>aopTest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.0.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.0.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.0.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.4</version>
    </dependency>
  </dependencies>
</project>

第一种方式,java代码声明:

这里实例中,我要声明一个aop来拦截dao层中的get开头的所有方法,首先建一个dao以及简单的额imp实现:

dao接口如下:

package com.ck.aopTest.dao;
import com.ck.aopTest.model.UserModel;

public interface MyAopDao {
    public void getUser();
    public void getName(UserModel user);
    public void addUser();
}

简单的实现:

package com.ck.aopTest.dao.impl;
import org.springframework.stereotype.Repository;
import com.ck.aopTest.dao.MyAopDao;
import com.ck.aopTest.model.UserModel;

@Repository
public class MyAopDaoImpl implements MyAopDao {

    @Override
    public void getUser() {
        System.out.println("这是我的aop测试dao方法一");
    }
    @Override
    public void getName(UserModel userModel) {
        System.out.println("这是我的aop测试dao方法二");
    }
    @Override
    public void addUser() {
        System.out.println("这是我的aop测试dao方法三");
    }
}

然后声明一个aop:

package com.ck.aopTest.aop;
import java.util.Date;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import com.ck.aopTest.model.UserModel;

@Aspect
@Component
public class MyAop {

    @Pointcut("execution(public * com.ck.aopTest.dao.impl.*.get*(..))")
    private void aopTest() {

    }
    @Before("aopTest()")
    public void before() {
        System.out.println("调用dao方法前拦截" + new Date().getTime());
    }
    @After("aopTest()" + "&&args(user)")
    public void after(UserModel user) {
        System.out.println(user.getName());
        System.out.println("调用dao方法之后拦截" + new Date().getTime());
    }
    @Around("aopTest()")
    public void around(ProceedingJoinPoint pdj) {
        System.out.println("调用dao之前的环绕拦截" + new Date().getTime());
        try {
            pdj.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("调用dao之后的环绕拦截" + new Date().getTime());
    }
}

上述代码便是用java声明aop的核心代码,其中注解@Aspect的作用的就是告诉spring这是一个aop类,然后@Component就不用多说了,告诉spring这是一个需要扫描的类。

再往下,@Pointcut(“execution(public * com.ck.aopTest.dao.impl..get(..))”)正式声明需要拦截的切面,@Pointcut以及后边的额execution是固定的写法,execution后括号内的内容便是具体的切面,这里的意思是拦截所有public的任何返回值或者void的、命名空间是com.ck.aopTest.dao.impl下边的所有的类中的所有get开头的拥有任意多个参数的方法。

简单点说也就是当任何调用了com.ck.aopTest.dao.impl这个包中任何类中的get开头的方法,便会激活这个aop。

而紧接着上边这一段,我们看到了一个private void aopTest() 空的方法,实际上这个方法的作用是为这个aop切面声明一个名字,便于使用,也便于在多个aop切面时正常区分。

再后边的@Before、@After、@Around便是三个可选拦截方式,见名之意,分别是在上边声明的切面指明的方法调用之前执行、调用之后执行、以及环绕执行,调用之前和调用之后比较好理解,环绕的意思是在调用之前和之后都执行一定的逻辑。

从代码中可以看出,pdj.proceed();之前和之后各打印了两行数据,pdj.proceed();就代表了继续执行,如果是了解filter的应该很容易想到这个方法实际上和chain.doFilter很像,可以理解成放行。

在这三个注解之后需要指定要使用的切面,即@Pointcut声明的切面,指定名称就行。

从代码中可以看到有一个地方后边加了“&&args(UserModel user)”,意思是指定形参,也就是说指定的切面中有效方法的参数,例如上边dao中的getName方法有一个UserModel类型的参数,这里便可以使用。

主要代码写好了,接下来还有个必不可少的步骤,既然是spring项目,是spring的aop,那么自然需要配置spring文件,指明需要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:context="http://www.springframework.org/schema/context" "
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:component-scan base-package="com.ck.aopTest.*" />
</beans>

为了验证这里的aop是否真的有效,我写了一个junit测试:

package com.ck.aopTest.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ck.aopTest.dao.MyAopDao;
import com.ck.aopTest.model.UserModel;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring.xml")
public class AopTest {
    @Autowired
    private MyAopDao myAopDao;

    @Test
    public void aopTest2() {
        UserModel user = new UserModel();
        myAopDao.getName(user);
    }
}

按理说,这里运行测试方法后应该打印出很多条输出,但是遗憾的是结果只是打印出了dao中的一条输出,原因是spring配置中并没有启用aop,正确的配置应该是下边这样:

<?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: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.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> 

    <aop:aspectj-autoproxy />
    <context:component-scan base-package="com.ck.aopTest.*" />   

</beans>

我们需要再文件头加入

xmlns:aop=”http://www.springframework.org/schema/aop”

,以及

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-4.0.xsd

除此之外,还要启用aop:

<aop:aspectj-autoproxy />

再次运行测试方法会看到控制台如下:

由此证明这个aop是有效的。

第二种方式,配置文件配置:

同样的,这里还是用之前的dao以及对应的impl,因此这段代码便不再重复,不一样的是具体的aop类如下:

package com.ck.aopTest.aop;
public class MyAop2 {
    public void before2() {
        System.out.println("这是我的使用注解的aop,调用dao之前拦截");
    }
}

可以看到这个类实际上也是极致简单,普通类,普通方法,没有任何特别,然后我们要做的是在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: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.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> 

    <aop:aspectj-autoproxy />
    <bean id="myAop2" class="com.ck.aopTest.aop.MyAop2"></bean>
    <aop:config>
      <aop:pointcut expression="execution(public * com.ck.aopTest.dao.impl.*.add*(..))" id="aopTest1"/>
      <aop:aspect id="myAopTest2" ref="myAop2">
        <aop:before method="before2" pointcut-ref="aopTest1"/>
      </aop:aspect>
    </aop:config>
    <context:component-scan base-package="com.ck.aopTest.*" />

</beans>

至于这里配置内容的具体解释,我想通过我对第一种方式的解释后,也没有太大必要再说,稍微一对比就会一清二楚。

同样的,这里只演示了before,至于after和round的配置应该也很容易就可以根据before推理出来。

时间: 2024-10-24 03:00:16

spring面向切面aop拦截器的相关文章

Spring面向切面(AOP)

AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志.事务.权限等,Struts2的拦截器设计就是基于AOP的思想. AOP的基本概念 Aspect(切面):通常是一个类,里面可以定义切入点和通知 JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用. Advice(通知):AOP在特定的切入点上执行的增强处理,有before.after.afterReturning.afterThrowing.around Pointcut(切入点):AOP框架创

Spring面向切面编程(二)简单AOP实例

简单实现一个用户登陆的功能,在用户登陆之前进行日志打印,用户登陆之后进行登陆成功日志打印. Maven添加Spring jar spring面向切面编程(一)AOP术语 添加Spring AOP的jar 参考:Maven添加Spring jar 还需添加: 创建User类: package com.user; public class User { private String username; private String password; public String getUsernam

Spring框架使用(控制反转,依赖注入,面向切面AOP)

参见:http://blog.csdn.net/fei641327936/article/details/52015121 Mybatis: 实现IOC的轻量级的一个Bean的容器 Inversion of control 控制反转:由容器控制程序之间的关系,不是程序代码操作 Depend Inject 依赖注入 Aspect oriented programming 面向切面编程 Spring能帮助我们根据配置文件创建及组装对象之间的依赖关系: Spring面向切面编程能帮助我们无耦合的实现日

Spring 面向切面编程(AOP)

Spring 系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Control – IOC) 理解依赖注入(DI – Dependency Injection) Bean XML 配置(1)- 通过XML配置加载Bean Bean XML 配置(2)- Bean作用域与生命周期回调方法配置 Bean XML 配置(3)- 依赖注入配置 Bean XML 配置(

Spring面向切面编程

  1.面向切面编程(AOP)的概念:把项目中需要在多处用到的功能,比如日志.安全和事物等集中到一个类中处理,而不用在每个需要用到该功能的地方显式调用.   2.术语解释:        横切关注点:分布应用于多处的功能        切面:横切关注点可以被模块化为一个类,这个类被称为一个切面        通知(advice):切面要完成的工作.Spring的通知有5种类型:before.after.after-returning.after-throwing和around这五种类型.    

Spring面向切面 --- AspectJ --- 简单使用

Spring面向切面 --- AspectJ --- 简单使用 昨天回复说说的时候突然写下了下面的一段话:分享一下: <!--******************************************* 其实经过的记忆是可以进行道德化的篡改的,就像夏目漱石的<我是猫>:但是不管怎么改,真正的事实是由每一个人的碎片拼起来的:经济学里计算成本的是在计算将来的成本而不是过去的成本,就像动漫<未来日记>一样:过去发生的事情总是在影响着将来,但是过去发生的事情却不能充当将来下

spring boot中注册拦截器

拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式.在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作. 如何在spring boot中添加拦截器? 1.首先自己实现一个拦截器 import org.springframework.web.ser

spring mvc 方法注解拦截器

应用场景,在方法级别对本次调用进行鉴权,如api接口中有个用户唯一标示accessToken,对于有accessToken的每次请求可以在方法加一个拦截器,获得本次请求的用户,存放到request或者session域. python中,之前在python flask中可以使用装饰器来对方法进行预处理,进行权限处理 先看一个实例,使用@access_required拦截: @api.route('/post_apply') @access_required def apply():     "&q

spring mvc中的拦截器小结 .

在spring mvc中,拦截器其实比较简单了,下面简单小结并demo下. preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现):      返回值:true表示继续流程(如调用下一个拦截器或处理器):              false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应: postHandle:后处理回调方法,实现处理器的后处理(但在渲