AspectJ

作者: 神豪VS勇士赢 | 来源:发表于2018-08-03 20:42 被阅读17次

基于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

相关文章

网友评论

      本文标题:AspectJ

      本文链接:https://www.haomeiwen.com/subject/aciuvftx.html