Spring中 AOP及AspectJ 代理使用

1. Spring 的AOP介绍

Spring 中 的AOP联盟为通知Advice定义了org.aoplliance.aop.Advice

Spring按照通知Advice在目标方法的连接点位置,可以分为5类:

  • 前置通知 org.springframework.aop.MethodBeforeAdvice 在目标方法执行前实施增强
  • 后置通知 org.springframework.aop.AfterReturningAdvice 在目标方法执行后实施增强
  • 环绕通知 org.aopalliance.intercept.MethodInterceptor 在目标方法执行前后实施增强
  • 异常抛出通知 org.springframework.aop.ThrowsAdvice 在方法抛出异常后实施增强
  • 引介通知 org.springframework.aop.IntroductionInterceptor 在目标类中添加一些新的方法和属性
1.1 MethodBeforeAdvice源码分析:
/**
 * Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}.
 * Used internally by the AOP framework; application developers should not need
 * to use this class directly.
 *
 * @author Rod Johnson
 */
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

	private MethodBeforeAdvice advice;


	/**
	 * Create a new MethodBeforeAdviceInterceptor for the given advice.
	 * @param advice the MethodBeforeAdvice to wrap
	 */
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}

	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}

}

如上图源码: invoke方法中先执行了advice 通知的方法,而后执行了目标方法。

  • 环绕通知,需要手动执行目标方法:
try{
   //前置通知
   //执行目标方法
   //后置通知
} catch(){
   //抛出异常通知
}    

其他通知请自行查看源码!!!

2. 基于aop 的切面编程

  • 让spring 创建代理对象,从spring容器中手动的获取代理对象。
2.1 demo样例如下:

需要导入的包如下:

核心:4 + 1

aop联盟(规范)、spring-aop(实现) 输入图片说明

2.2 需要编写的文件
  • beans.xml
  • AopTest.java
  • MyAspect.java
  • UserService.java
  • UserServiceImp.java

主要说下UserServiceImpl、beans.xml 、 AopTest.java、MyAspect.java:(如有不清楚,请自行查看码云源码 )

UserServiceImpl.java

public class UserServiceImp implements UserService {

	public void addUser() {
		System.out.println("d_aspect.a_xml.............a_jdk");
	}

	public void updateUser() {
		int i= 1/0;
		System.out.println("d_aspect.a_xml.............a_jdk");
	}

	public void deleteUser() {
		System.out.println("d_aspect.a_xml.............a_jdk");
	}

}

MyAspect切面类如下:

/**
 * @author liupenghao 切面类
 */
public class MyAspect implements MethodInterceptor{

	public Object invoke(MethodInvocation mi) throws Throwable {
		
		System.out.println("前3");
		Object obj = mi.proceed();
		System.out.println("后3");
		return obj;
	}
}

beans.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 
					http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- bean definitions here -->
	
	<!--配置目标类  -->
	<bean id="UserService" class ="com.uu.c_spring_aop.UserServiceImp"></bean>
	
	<!-- 配置切面类 -->
	<bean id="myaspect" class="com.uu.c_spring_aop.MyAspect"> </bean>
	
	<!--  
	aop 编程
	1.  导入命名空间
	2. 使用<app:config> 进行配置
		proxy-target-class       声明是否使用cglib
		aop:pointcut	切入点,从哪目标对象获得具体方法
		aop:advisor		特殊的切面,只有一个通知和一个切入点
			advice-ref 通知引入
			pointcut-ref 切入点引用
	
	3. 切入点表达式
		execution(* com.uu.c_spring_aop.*.*(..))
		选择方法	返回值任意				包
			
			
	
	
	
	-->
	<aop:config  proxy-target-class="true">
		<aop:pointcut expression="execution(* com.uu.c_spring_aop.*.*(..))" id="myPointCut"></aop:pointcut>
		<aop:advisor advice-ref="myaspect" pointcut-ref="myPointCut"/>
	</aop:config>
</beans>

AopTest 如下:


public class AopTest {

	@Test
	public void Test() {

		String xmlPath = "com/uu/c_spring_aop/beans.xml";
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
				xmlPath);
		UserService service = context.getBean("UserService",
				UserService.class);
		service.addUser();
		service.updateUser();
		service.deleteUser();
	}
}
2.3 基于AspectJ 的切面编程

与基于AOP编程不同的是,AspectJ提供了 按照通知Advice在目标方法的连接点位置的不同 而生成的实现类(如:AfterReturningAdviceInterceptor),用的时候只需配置通知方法即可。

可以简单的理解为:根据用户要在目标方法 实时操作的位置的不同,而实现的方法拦截器。

2.3.1 demo小案例

程序的实现需要的文件如下:

  • MyAspect.java
  • UserService.java
  • UserServiceImp.java
  • xmlTest.java
  • beans.xml

UserSerice、UserServiceImpl、xmlTest 文件和2.2的一致,不做赘述

MyAspect.javaq 如下:

public class MyAspect {

	public void myBefore(JoinPoint joinPoint) {
		System.out.println("前置通知:" + joinPoint.getSignature().getName());
	}

	public void MyAfterRetruning(JoinPoint joinPoint, Object ret) {
		System.out.println("后置通知: " + joinPoint.getSignature().getName() + ","
				+ ret);
	}

	public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println(" 前");
		Object obj = joinPoint.proceed();
		System.out.println("后");
		return obj;
	}

	public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
		System.out.println("抛出异常 通知:"+ e.getMessage());
	}
	
	public void myAfter(JoinPoint joinPoint){
		System.out.println("最终通知");
	}
	
}

beans.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 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 1 创建目标类 -->
	<bean id="userServiceId" class="com.uu.d_aspect.a_xml.UserServiceImp"></bean>
	<!-- 2 创建切面类(通知) -->
	<bean id="myAspectId" class="com.uu.d_aspect.a_xml.MyAspect"></bean>
	<!-- 3 aop编程 <aop:aspect> 将切面类 声明“切面”,从而获得通知(方法) ref 切面类引用 <aop:pointcut> 
		声明一个切入点,所有的通知都可以使用。 expression 切入点表达式 id 名称,用于其它通知引用 -->

	<aop:config>
		<aop:aspect ref="myAspectId">
			<aop:pointcut
				expression="execution(* com.uu.d_aspect.a_xml.UserServiceImp.*(..))"
				id="myPointCut" />
			<!-- 前置通知: method: 通知,及方法名 pointcut: 切入点表达式 pointcut-ref: 切入点引用 -->
			<!-- <aop:before method="myBefore" pointcut-ref="myPointCut" /> -->

			<!-- <aop:after-returning method="MyAfterRetruning" pointcut-ref="myPointCut" 
				returning="ret"/> -->

			<!-- <aop:around method="myAround" pointcut-ref="myPointCut" /> -->

			<aop:after-throwing method="myAfterThrowing"
				pointcut-ref="myPointCut" throwing="e" />
			<aop:after method="myAfter" pointcut-ref="myPointCut" />
		</aop:aspect>
	</aop:config>
</beans>
2.4 基于注解的配置

与基于xml配合相比,注解配置较为简单,可以做到强耦合,基于method进行切面的编程。再加上spring 强大的IOC(控制反转),DI(依赖注入),代码在实现功能的基础上,变得简洁明了,完美!!!

2.4.1demo小案例

所需的文件如下:

  • beans.xml
  • AnnoTest.java
  • MyAspect.java
  • UserService.java
  • UserServiceImp.java

UserServiceImpl.java

@Service("userServiceId")
public class UserServiceImp implements UserService {

	public void addUser() {
		System.out.println("d_aspect.b_anno.............a_jdk");
	}

	public void updateUser() {
		//int i= 1/0;
		System.out.println("d_aspect.b_anno.............a_jdk");
	}

	public void deleteUser() {
		System.out.println("d_aspect.b_anno.............a_jdk");
	}

}

MyAspect.java

@Component
@Aspect
public class MyAspect {
	
	@Pointcut("execution(public * com.uu.d_aspect.b_anno.UserServiceImp.*(..))")
	public void myPointCut(){
		
	}

	@After("myPointCut()")
	public void myAfter(JoinPoint joinPoint){
		System.out.println("最终通知");
	}
	
}

beans.xml

<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.xsd
       					   http://www.springframework.org/schema/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd">
	
	<!-- 1. 扫描 注解类 -->
	<context:component-scan base-package="com.uu.d_aspect.b_anno"></context:component-scan>
	<!-- 2. 确定 aop 注解生效 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

3. 源码地址:

GitHub-下载地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值