spring aop用法

介绍


在开发中我们经常使用oop这种纵向结构来开发,但是却会出现一些横切的功能。譬如,日志记录的功能,我们需要在每个方法执行的详细信息通过日志记录,但是我们为每个方法去写日志,明显不合理。再如异常处理功能,我们需要在每个方法执行抛出的异常都专门处理都不合理。这样就需要AOP面向切面开发来处理横切问题。

AOP术语


  1. 通知(advice):
    通知主要是定义切面是什么以及何时使用。
    Before:在接合点之前执行通知。
    AfterReturning:在接合点执行完成之后执行通知。
    AfterThrowing:如果从接合点抛出了任何异常,都执行通知。
    After:接合点执行完成之后,无论是否抛出了异常,都执行通知。
    Around:在接合点周围执行通知,意思就是可能在接合点之前执行,也可能在接合点之后执行。
  2. 连接点(join point):
    意思就是代码中的点,在这个点上开始玩切面。效果肯定是向应用程序中插入额外的逻辑。
  3. 切点(point cut):
    用来选择需要执行一个或者多个连接点的表达式。
  4. 切面(aspect):
    切面就是切点和通知的结合。
  5. 织入(weaving):
    将方面与目标对象结合在一起的过程。
  6. 引入(introduce):
    动态地为已经存在的类添加属性和方法。

XML方式实现AOP


配置文件:

    <context:component-scan base-package="cn.spy"></context:component-scan>
    <context:annotation-config></context:annotation-config>
    <aop:config>
        <aop:pointcut expression="execution(* cn.spy.service.impl.MyServiceImpl.*(..))" id="pc"/>
        <aop:aspect ref="myAop">
            <aop:before method="beforeExecute" pointcut-ref="pc"/>
            <aop:after method="afterExecute" pointcut-ref="pc"/>
        </aop:aspect>
    </aop:config>

强制设置使用cglib代理:<aop:config proxy-target-class="true">

业务类和接口

public interface MyService {
    public void serviceMed();
}

@Component("myService")
public class MyServiceImpl extends BaseLog implements MyService{

    @Override
    public void serviceMed() {
        System.out.println("业务逻辑方法");
    }
}

切面类:

@Component("myAop")
public class MyAop extends BaseLog {
    
    public void beforeExecute() {
        System.out.println("before execute");
    }
    
    public void afterExecute() {
        System.out.println("after execute");
    }
}

测试类:

public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        MyService myService = (MyService) context.getBean("myService");
        myService.serviceMed();
    }

结果:


1.jpg

注解方式实现AOP


切面类:

@Component("myAop")
@Aspect
public class MyAop extends BaseLog {
    
    @Pointcut("execution(* cn.spy.service.impl.MyServiceImpl.*(..))")
    public void cutMethod() {
        
    }
    
    @Before("cutMethod()")
    public void beforeExecute() {
        System.out.println("before execute");
    }
    
    @After("cutMethod()")
    public void afterExecute() {
        System.out.println("after execute");
    }
}

强制使用cglib代理:@EnableAspectJAutoProxy(proxyTargetClass=true)

aop自定义注解实现记录操作日志


  1. 自定义注解
/**
 * 日志操作注解
 */
@Documented
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogOperation {
    /**
     *  操作所属的模块
     * @return
     */
    public String module() default "";

    /**
     * 操作
     * @return
     */
    public String operation() default "";

}
  1. 实现切面类
@Slf4j
@Component
@Aspect
public class LogAspect {

    @Autowired
    private MachineBO machine;

    @Autowired
    private LogMapper logMapper;

    @Pointcut("@annotation(com.sunpy.permissionservice.log.LogOperation)")
    public void logPoint() {

    }

    @AfterReturning(pointcut = "logPoint()", returning = "result")
    public void doLog(JoinPoint joinPoint, Object result) {
        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取切入点所在的方法
        Method method = signature.getMethod();
        // 获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        
        LogOperation logOperation = method.getAnnotation(LogOperation.class);

        Log log = new Log();
        log.setLogModule(logOperation.module());
        log.setLogOperation(logOperation.operation());
        log.setLogClazz(className);
        log.setLogMethod(method.getName());
        log.setLogMethodResult(method.getReturnType().getName());
        StringBuilder sb = new StringBuilder();

        for (Parameter parameter : method.getParameters()) {
            sb.append(parameter.getParameterizedType().getTypeName());
            sb.append(",");
        }

        log.setLogMethodParam(sb.toString());
        insertLog(log);
    }

    private void insertLog(Log log) {
        long logId = new SnowFlakeIdUtil(machine.getWorkerId(), machine.getDatacenterId()).genNextId();
        log.setLogId(logId);
        log.setCreateTime(TimeUtil.getLocalDateTime());
        logMapper.insert(log);
    }


}
  1. 使用:

切点表达式


  1. 表达式语法:
execution(<scope> <return-type><fully-qualified-class-name>.*(parameters))
  1. 例子:
    execution(* cn.spy.service.impl.MyServiceImpl.(..))
    解释:匹配cn.spy.service.impl.MyServiceImpl类下的所有方法
    execution(public void cn.spy.service.impl.MyServiceImpl.
    (..))
    解释:匹配cn.spy.service.impl.MyServiceImpl类下的public void xx();方法。
    execution(public void cn.spy.service.impl.MyServiceImpl.*(String,..))
    解释:匹配cn.spy.service.impl.MyServiceImpl类下第一个参数为String类型,无返回值的所有公共方法。
  2. 通配符:
    ..该通配符匹配方法定义中的任何数量的参数。(也可以匹配任意数量的包)
    +该通配符匹配给定类的任何子类。
    *该通配符匹配任意数量的字符。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容