Spring AOP(前置通知方法 、后置通知方法 、环绕通知方法 )与拦截器的使用

AOP(Aspect Oriented Programming)也就是面向切面编程的技术。AOP基于IoC基础,是对OOP的有益补充。AOP是代码之间解耦的一 种实现。可以这样理解,面向对象编程是从静态角度考虑程序结构,面向切面编程是从动态角度考虑程序运行过程。AOP将应用系统分为两部分:
(1)核心业务逻辑(Core Business Concerns)。
(2)横向的通用逻辑,也就是所谓的切面(Crosscutting Enterprise Concerns)。
例如,所有大中型应用都要涉及的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。

AOP的底层实现原理实际是Java语言的动态代理机制。AOP 代理是由AOP框架动态生成一个对象,该对象可作为目标对象使用。AOP代理包含了目标对象的全部方法,但代理中的方法与目标对象的方法存在差异: AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。Spring 的AOP通常和IoC配合使用,需要程序员参与的有3个部分:
(1)定义普通业务组件。
(2)定义切入点。一个切入点可以横切多个业务组件。
(3)定义增强处理。增强处理就是在AOP框架为普通业务组件织入的处理动作。
Spring有如下两种方式来定义切入点和增强处理:
(1)annotation 配置方式。使用@Aspect、 @Pointcut 等Annotation标注切入点和增强处理。
(2)xml 配置方式。使用xml配置文件定义切入点和增强处理。


我使用的是上一个学习crud操作的代码(MVC),稍作修改完成这个知识点的学习。
使用Spring实现mysql数据库的CRUD操作

①AOP的前置通知方法 、后置通知方法 、环绕通知方法

首先导入相关的包:
Spring AOP(前置通知方法 、后置通知方法 、环绕通知方法 )与拦截器的使用_第1张图片

(1)定义一个java文件来使用AOP技术。(LogAdvice.java(日志通知切面))

LogAdvice.java

package com.advice;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;


public class LogAdvice {
	//前置通知方法
	public void myBeforeAdvice(JoinPoint joinPoint){
		String methodname = joinPoint.getSignature().getName();
        System.out.println("Before前置通知——执行"+methodname+"方法前");
    }
	
	//后置通知方法
    public void myAfterAdvice(JoinPoint joinPoint){
    	String methodname = joinPoint.getSignature().getName();
        System.out.println("执行"+methodname+"方法后——After后置通知");
    }
    
    //环绕通知方法
    public void myAroundAdvice(ProceedingJoinPoint point) throws Throwable{
    	String methodname = point.getSignature().getName();
    	System.out.println("环绕通知,执行"+methodname+"方法前");
        //选择执行
        point.proceed();
        System.out.println("环绕通知,执行"+methodname+"方法后");
    }
}

(2)在applicationContext.xml文件做相关bean配置(部分代码)

<bean id="userDao" class="com.dao.UserDao"/>
    <bean id="userService" class="com.service.UserService">
    	<property name="userDao" ref="service"></property>
    </bean>
    <bean id="logAdvice" class="com.advice.LogAdvice"/>
    
    <aop:config>
       <!-- 配置一个切面 -->
       <aop:aspect id="logaop" ref="logAdvice" order="1">
           <!-- 定义切入点,表示对service的所有方法都进行拦截 -->
           <!-- 
           expression:用来匹配执行方法的连接点
           	第一个*表示匹配任意的方法的返回值
           	第一个..表示service包及其子包
           	第二个*表示所有类
           	第三个*表示所有方法
           	第二个..表示方法的任意参数个数
            -->
           <aop:pointcut expression="execution(* com.service.*.*(..))" id="testpointcut"/>
           <!-- 定义前置通知 -->
           <aop:before method="myBeforeAdvice" pointcut-ref="testpointcut"/>
           <!-- 定义后置通知 -->
           <aop:after method="myAfterAdvice" pointcut-ref="testpointcut"/>
           <!-- 定义环绕通知 -->           
           <aop:around method="myAroundAdvice" pointcut-ref="testpointcut"/>
       </aop:aspect>
    </aop:config>
</beans>

再写个测试类跑起来就可以了。


②通过拦截器判断用户是否可以执行目标代码的方法

(1)AuthorityInterceptor.java(用户权限拦截器)
功能:
admin用户可以执行add()和update()方法
register用户可以执行add()方法,但不可执行update()方法
other用户都不可以执行add()和update()方法

package com.interceptor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import com.bean.User;

public class AuthorityInterceptor implements MethodInterceptor {

	private User user;
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
	
	public Object invoke(MethodInvocation arg0) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("拦截器==权限验证开始");
		String username=this.user.getUsername();
		String methodName = arg0.getMethod().getName();
		if(!username.equals("admin")&&!username.equals("register")) {
			System.out.println("没有任何执行权限");
			return null;
		}
		else if(username.equals("register")&&methodName.equals("update")) {
			System.out.println("register用户没有修改权限");
			return null;
		}
		else {
			Object object = arg0.proceed();
			System.out.println("拦截器==权限验证结束");
			return object;
		}
	}

}

(2)LogInterceptor.java(用户操作日志拦截器)

package com.interceptor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class LogInterceptor implements MethodInterceptor {

	public Object invoke(MethodInvocation arg0) throws Throwable {
		// TODO Auto-generated method stub
		String methodName = arg0.getMethod().getName();
		Object object = arg0.proceed();
		System.out.println("拦截器==日志记录:尝试执行"+methodName+"方法");
		return object;
	}
}

(3)在applicationContext.xml文件做相关bean配置(部分代码)

   <bean id="admin" class="com.bean.User">
  		<property name="username" value="admin"></property>
  		<property name="password" value="123456"></property>
  	</bean>
  	
  	<bean id="register" class="com.bean.User">
  		<property name="username" value="register"></property>
  		<property name="password" value="654321"></property>
  	</bean>
  	
  	<bean id="other" class="com.bean.User">
  		<property name="username" value="other"></property>
  		<property name="password" value="666666"></property>
  	</bean>
  	<!--  -->
  	<bean id="logInterceptor" class="com.interceptor.LogInterceptor"/>
  	
  	<bean id="authorityInterceptor" class="com.interceptor.AuthorityInterceptor">
  		<!-- admin/register/other -->
  		<property name="user" ref="admin"></property>
  	</bean>
  	
  	<bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
  		<property name="target" ref="userDao"></property>
  		<property name="interceptorNames">
  			<list>
  				<value>authorityInterceptor</value>
  				<value>logInterceptor</value>
  			</list>
  		</property>
  	</bean>

激动人心的时刻到了,我们把成品跑起来!

测试类:

package com.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.service.UserService;

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		ClassPathXmlApplicationContext l = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		UserService service = l.getBean("userService",UserService.class);
		
		
		service.add();
		l.close();//关闭流
		service.update();
		l.close();
	}

}

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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <bean id="admin" class="com.bean.User">
  		<property name="username" value="admin"></property>
  		<property name="password" value="123"></property>
  	</bean>
  	
  	<bean id="register" class="com.bean.User">
  		<property name="username" value="register"></property>
  		<property name="password" value="123"></property>
  	</bean>
  	
  	<bean id="other" class="com.bean.User">
  		<property name="username" value="other"></property>
  		<property name="password" value="123"></property>
  	</bean>
  	<!--  -->
  	<bean id="logInterceptor" class="com.interceptor.LogInterceptor"/>
  	
  	<bean id="authorityInterceptor" class="com.interceptor.AuthorityInterceptor">
  		<!-- admin/register/other -->
  		<property name="user" ref="admin"></property>
  	</bean>
  	
  	<bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
  		<property name="target" ref="userDao"></property>
  		<property name="interceptorNames">
  			<list>
  				<value>authorityInterceptor</value>
  				<value>logInterceptor</value>
  			</list>
  		</property>
  	</bean>
    
    <bean id="userDao" class="com.dao.UserDao"/>
    <bean id="userService" class="com.service.UserService">
    	<property name="userDao" ref="service"></property>
    </bean>
    <bean id="logAdvice" class="com.advice.LogAdvice"/>
    
    <aop:config>
       <!-- 配置一个切面 -->
       <aop:aspect id="logaop" ref="logAdvice" order="1">
           <!-- 定义切入点,表示对service的所有方法都进行拦截 -->
           <!-- 
           expression:用来匹配执行方法的连接点
           	第一个*表示匹配任意的方法的返回值
           	第一个..表示service包及其子包
           	第二个*表示所有类
           	第三个*表示所有方法
           	第二个..表示方法的任意参数个数
            -->
           <aop:pointcut expression="execution(* com.service.*.*(..))" id="testpointcut"/>
           <!-- 定义前置通知 -->
           <aop:before method="myBeforeAdvice" pointcut-ref="testpointcut"/>
           <!-- 定义后置通知 -->
           <aop:after method="myAfterAdvice" pointcut-ref="testpointcut"/>
           <!-- 定义环绕通知 -->           
           <aop:around method="myAroundAdvice" pointcut-ref="testpointcut"/>
       </aop:aspect>
    </aop:config>
</beans>

修改xml文件的联系用户id来显示不同用户下的打印结果。

  	<bean id="authorityInterceptor" class="com.interceptor.AuthorityInterceptor">
  		<!-- admin/register/other -->
  		<property name="user" ref="admin"></property>
  	</bean>

(1)admin
Spring AOP(前置通知方法 、后置通知方法 、环绕通知方法 )与拦截器的使用_第2张图片
(2)register
Spring AOP(前置通知方法 、后置通知方法 、环绕通知方法 )与拦截器的使用_第3张图片
(3)other
Spring AOP(前置通知方法 、后置通知方法 、环绕通知方法 )与拦截器的使用_第4张图片

你可能感兴趣的:(spring)