基于Java语言的AOP框架
切入点表达式(希望哪些方法和通知类关联形成切面)
语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
修饰符,一般省略
返回值,不能省略
包,[省略]
类,[省略]
方法名,不能省略
(参数)
throws ,可省略
execution(
修饰符 一般省略
返回值 String 指定返回类型(意义不大)
一般使用*表示任意返回类型
包的路径
1)明确的包:com.qf.service[一个固定的服务层包下面包含多个模块类]
2)按照模块分包
com.qf.student.service
com.qf.log.service
抽取:com.qf..service[需要把模块抽取出来]
3)包含子包的包
com.qf.service
com.qf.service.impl
抽取:com.qf.service..(两个点)
类: 指定具体的类StudentServiceImpl[意义不大]
指定包下面的所有类:
方法名称 指定具体的方法:add()[意义不大]
指定所有的方法:*
参数 指定具体类型的参数:String[意义不大]
指定任意的参数:(..)
)
掌握:
execution(* com.qf.service...(..)) //service下所有子包(含自己)
execution(* com.qf..service..(..))//任意模块
execution( com.qf.service..(..))//任意类、方法、参数
AspectJ 通知类型
before:前置通知(应用:各种校验)在方法执行前执行,如果通知抛出异常,阻止方法运行。
afterReturning:后置通知(应用:常规数据处理)方法正常返回后执行,如果方法中抛出异常,通知无法执行,必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知(应用:十分强大)方法执行前后分别执行,可以阻止方法的执行,必须手动执行目标方法。
AspectJ编写通知:
1,不需要实现接口
2,方法名称任意
3,参数引入切入点:
前置JoinPoint (后置多返回Object参数,同时Object必须在第二个参数的位置),环绕ProceedingJoinPoint
(注意引包:aspectj下面:org.aspectj.lang.JoinPoint)
XML方式实践
开发流程
第一步:创建目标接口和实现类
@Repository("aspectJDao")
public class AspectJDaoImpl implements AspectJDao {
@Override
public void addAspectJ() {
Log.info("addAspectJ");
}
@Override
public String printAspectJ() {
return "我是返回值AspectJ";
}
}
@Service("aspectJService")
public class AspectJServiceImpl implements AspectJService {
@Qualifier("aspectJDao")
@Autowired
private AspectJDaoImpl aspectJDao;
@Override
public void addAspectJ() {
aspectJDao.addAspectJ();
}
@Override
public String printAspectJ() {
Log.info("我是Service啊啊");
return aspectJDao.printAspectJ();
}
}
第二步:创建自定义通知类
不需要实现接口
方法名称任意
@Component("aspectJLogAdvice")
public class AspectJLogAdvice {
public void myBefore(JoinPoint joinPoint){
Log.info("我是前置的Log信息");
}
public void myAfter(JoinPoint joinPoint, Object res){
Log.info("我是后置的Log信息"+"返回的信息是:"+res);
}
public Object myAround(ProceedingJoinPoint proceedingJoinPoint){
Object proceed = null;
try {
Log.info("我是环绕前置");
proceed = proceedingJoinPoint.proceed();
Log.info("我是环绕后置");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return proceed;
}
}
注意是:
1)自定义的。参数需要指定好。
2)JoinPoint 必须作为第一个参数,返回值Object res只能作为第二个参数,如果置换顺序会报错,要求索引为0的位置就是JoinPoint
第三步:AOP全自动编程
目的一致:让通知和切入点关联形成切面。
使用AspectJ有单独的配置节点,需要关联通知类。
每一种通知方法,都有具体的节点来实现。
核心配置:
通知类的对象引用
<aop:config>
<aop:aspect ref="aspectJLogAdvice">
<aop:pointcut id="myPoint" expression="execution( * com.zyh.service..*.*(..))"></aop:pointcut>
<aop:before method="myBefore" pointcut-ref="myPoint"></aop:before>
<!--<aop:after-returning method="myAfter" pointcut-ref="myPoint" returning="res" ></aop:after-returning>-->
<!--<aop:around method="myAround" pointcut-ref="myPoint" ></aop:around>-->
</aop:aspect>
</aop:config>
@Component("aspectJLogAdvice")
public class AspectJLogAdvice {
public void myBefore(JoinPoint joinPoint){
Log.info("我是前置的Log信息");
}
public void myAfter(JoinPoint joinPoint, Object res){
Log.info("我是后置的Log信息"+"返回的信息是:"+res);
}
public Object myAround(ProceedingJoinPoint proceedingJoinPoint){
Object proceed = null;
try {
Log.info("我是环绕前置");
proceed = proceedingJoinPoint.proceed();
Log.info("我是环绕后置");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return proceed;
}
}
测试类如下所示:
/**
* 这个是测试前置
*/
@Test
public void testAspectJServiceBefore(){
ClassPathXmlApplicationContext classPathXmlApplicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
AspectJService aspectJService = (AspectJService) classPathXmlApplicationContext.getBean("aspectJService");
aspectJService.addAspectJ();
}
输出结果如下所示: 这个是前置输出结果
image.png
其他情况一样 就不进行测试了 只需要修改一下配置文件就可以了。
配置文件中的依赖如下所示:
image.png





网友评论