Spring AOP(四)-AspectJ实现AOP

一、AspectJ实现AOP

Aspect定义:是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
Spring2.0之后 为了简化 AOP编程,支持AspectJ 技术
@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面。
新版本Spring框架,建议使用AspectJ方式来开发AOP ,而不需要使用传统 Spring AOP 编程。
@Aspect是定义切面

二、通知的类型

@Before 前置通知,相当于BeforeAdvice
@AfterReturning 后置通知,相当于AfterReturningAdvice
@Around 环绕通知,相当于MethodInterceptor
@AfterThrowing抛出通知,相当于ThrowAdvice
@After 最终final通知,不管是否异常,该通知都会执行无论程序是否正常执行,最终通知的代码会得到执行 类似于 try{}cathc{} finally{}
1.切点的表达式定义
标识切面织入到哪些类的那些方法当中,通过execution函数,可以定义切点的方法切入。
语法: execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
2.特殊符号
a: * 代表0到多个任意字符
b: .. 放在方法参数中 ,代表任意个参数 ,放在包名后面表示当前包及其所有子包路径
c: + 放在类名后,表示当前类及其子类,放在接口后,表示当前接口及其实现类
3.举例说明
a:execution(public * *(..)) 表示任意的public方法
b:execution(* set*(..)) 表示任意包含以set字符开头的方法
c:execution(* com.tz.spring.dao.impl.*.*(..)) 表示com.tz.spring.dao.impl的任意类的任意方法
d:execution(* com.tz.spring.dao..*.*(..))
表示com.tz.spring.dao包下面的所有方法以及所有子包下面的所有方法
e:execution(* com.tz.spring.dao.UserDao+.*(..))

f:execution(* add(String,int)) 带包任意返回类型的add方法 有两个参数,类型分别为String,int

三、AspectJ+spring的环境搭建

1. 导入AspectJ的开发包(AspectJ依赖AOP的jar包)

2.引入aop的约束

3.基于xml的配置
首先创建一个IUserDao 的接口
public interface IUserDao {
	public void addUser();
	public void getUser();
	public void updateUser();
	public void deleteUser();
}
实现这个接口
import org.springframework.stereotype.Component;

import com.dqsy.spring.dao.IUserDao;
@Component(value="userDao")
public class IUserDaoImpl implements IUserDao {
	@Override
	public void addUser() {
		// TODO Auto-generated method stub
			System.out.println("添加用户");
	}
	@Override
	public void getUser() {
		// TODO Auto-generated method stub
		System.out.println("查找用户");
	}
	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("更改用户");
	}
	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("删除用户");
		int i = 1/0;
	}
}
编写切面MyAspect
package com.dqsy.spring.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
/**
 * 定义通知,基于XML配置的方式
 * @author Administrator
 *
 */
public class MyAspect {
	 //定义前置通知
	public void beforeAdvice(){
		System.out.println("前置通知,方法之前运行");
	}
	 // 后置通知
	public void afterAdvice(){
		System.out.println("后置通知,方法之后运行");
	}
	 //定义后置通知,含返回值
	public void afterAdvice(Object result){
		System.out.println("后置通知,方法之后运行,带返回值  : " + result);
	}
	 // 定义环绕通知
	public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("环绕通知,方法之前运行");
		 //这个表示目标对象的方法的运行
		pjp.proceed();
		System.out.println("环绕通知,方法之后运行");
	}
	 //定义异常通知
	public void afterThrowingAdvice(){
		System.out.println("异常通知");
	}
	 //定义异常通知
	public void afterThrowingAdvice(Exception ex){
		System.out.println("异常通知 " + ex.toString());
	}
	 // 最终通知
	public void lastAdvice(){
		System.out.println("最终通知");
	}
}
编写applicationContext.xml
	<!-- 注册UserDao -->
	<bean id="userDao" class="com.dqsy.spring.dao.impl.IUserDaoImpl"></bean>
	<!-- 注册切面 -->
	<bean id="myAspect" class="com.dqsy.spring.aspect.MyAspect"></bean>
	<!-- AspectJ的AOP配置 -->
	<aop:config>
	<!-- * add*(..) : 第一个*表示包路径,空格,add*:表示方法名称的表达式匹配, (..) :表示方法的参数 -->
		<aop:pointcut expression="execution(* add*(..))" id="beforePointCut" />
		<aop:pointcut expression="execution(* update*(..))" id="afterPointCut" />
		<aop:pointcut expression="execution(* get*(..))" id="aroundPointCut" />
		<aop:pointcut expression="execution(* delete*(..))" id="throwingPointCut" />
		<aop:pointcut expression="execution(* delete*(..))" id="lastPointCut" />
<!-- 这里是配置切面的通知/顾问 的方法 -->
		<aop:aspect ref="myAspect">
			<aop:before method="beforeAdvice" pointcut-ref="beforePointCut"/>
			<aop:after-returning method="afterAdvice(java.lang.Object)" 
			pointcut-ref="afterPointCut" returning="result"/>
			<aop:around method="aroundAdvice" pointcut-ref="aroundPointCut"/>
			<aop:after-throwing method="afterThrowingAdvice(java.lang.Exception)" 
			pointcut-ref="throwingPointCut" throwing="ex"/>
			<aop:after method="lastAdvice" pointcut-ref="lastPointCut"/>
		</aop:aspect>
	</aop:config>
编写测试方法
package com.dqsy.spring.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.dqsy.spring.dao.IUserDao;

public class AspectJTest {
	private ApplicationContext ctx=null;
	@Before
	public void init(){
		ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
	}
	@Test
	public void aspectJTest(){
		IUserDao userDao = (IUserDao) ctx.getBean("userDao");
		userDao.addUser();
		System.out.println();
		userDao.getUser();
		System.out.println();
		userDao.updateUser();
		System.out.println();
		userDao.deleteUser();
	}
}
结果:

基于注解的配置
同样的我们重新写一个MyAspectAnnotation基于注解的切面
package com.dqsy.spring.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspectAnnotation {
	//定义前置通知
		@Before(value="execution(* add*(..))")
		public void beforeAdvice(){
			System.out.println("前置通知,方法之前运行");
		}
		 // 后置通知
		@AfterReturning(value="execution(* update*(..))")
		public void afterAdvice(){
			System.out.println("后置通知,方法之后运行");
		}
		 //定义后置通知,含返回值
		@AfterReturning(value="execution(* update*(..))", returning="result")
		public void afterAdvice(Object result){
			System.out.println("后置通知,方法之后运行,带返回值  : " + result);
		}
		 // 定义环绕通知
		@Around(value="execution(* get*(..))")
		public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
			System.out.println("环绕通知,方法之前运行");
			 //这个表示目标对象的方法的运行
			pjp.proceed();
			System.out.println("环绕通知,方法之后运行");
		}
		 //定义异常通知
		@AfterThrowing(value="execution(* delete*(..))")
		public void afterThrowingAdvice(){
			System.out.println("异常通知");
		}
		 //定义异常通知
		@AfterThrowing(value="execution(* delete*(..))", throwing="ex")
		public void afterThrowingAdvice(Exception ex){
			System.out.println("异常通知 " + ex.toString());
		}
		 // 最终通知
		@After(value="execution(* delete*(..))")
		public void lastAdvice(){
			System.out.println("最终通知");
		}
}


重新写一个配置文件
	<!-- 注册IUserDao -->
	 <bean id="userDao" class="com.dqsy.spring.dao.impl.IUserDaoImpl"></bean> 
	
	<!-- 注册MyAspect -->
	<bean id="myAspect" class="com.dqsy.spring.aspect.MyAspectAnnotation"></bean>
	<!-- 开启aop的自动扫入  -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


测试结果同上一样
我们也可以通过前面的学习,通过注解将bean自动装配,同样也是ok的


四、小结

AOP是面向对象编程的一个强大补充。通过AspectJ,我们现在可以把之前分散在应用各处的
行为放入可重用的模块中。我们显示地声明在何处如何应用该行为。这有效减少了代码冗
余,并让我们的类关注自身的主要功能。

Spring提供了一个AOP框架,让我们把切面插入到方法执行的周围。现在我们已经学会如何
把通知织入前置、后置和环绕方法的调用中,以及为处理异常增加自定义的行为。
关于在Spring应用中如何使用切面,我们可以有多种选择。通过使用@AspectJ注解和简化
的配置命名空间,在Spring中装配通知和切点变得非常简单。

最后,当Spring AOP不能满足需求时,我们必须转向更为强大的AspectJ。对于这些场景,我
们了解了如何使用Spring为AspectJ切面注入依赖。

此时此刻,我们已经覆盖了Spring框架的基础知识,了解到如何配置Spring容器以及如何为
Spring管理的对象应用切面。正如我们所看到的,这些核心技术为创建松散耦合的应用奠定
了坚实的基础。






















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

奋斗的小巍

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

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

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

打赏作者

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

抵扣说明:

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

余额充值