基于Java配置的AOP

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/carson0408/article/details/86182300

        本文主要讲解的是AOP的内容,代码中将用Java配置代替xml配置。

        Spring的AOP的存在则是为了解耦。虽然OOP是很好的编程思想,但是还是会出现大量的代码复制的情况,从而会造成代码的冗余。在OOP中只能通过继承类和实现接口,来使代码的耦合度增强,且类继承只能为单继承,阻碍更多行为添加到一组类上,而AOP的出现则弥补了OOP的不足,Spring支持AspectJ声明的注解式切面编程。AOP即可以动态注入,使得一些重复使用的代码使用注解即可完成,而不需要重复编写,使程序更加简洁灵活。

        本文的示例主要是对AspectJ编程中基于注解拦截和基于方法规则拦截两种方式。

1.pom文件

        首先在pom文件中配置本文示例中需要的jar包。主要包括spring本身注解相关的包以及aspectj相关的包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.carson</groupId>
    <artifactId>aop</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>


    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <!-- sring aop 支持-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <!--aspectj 支持-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.5</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.5</version>
        </dependency>

    </dependencies>>


</project>

2.基于注解拦截

1.编写拦截规则的注解

其中注解本身没有功能,和xml一样,就是一种配置。注解的功能的实现来自于使用这个注解的地方。

package com.carson.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 编写拦截规则的注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
    String name();
}

2.编写使用注解的被拦截类

package com.carson.aop;

import org.springframework.stereotype.Service;

/**
 * 编写使用注解的被拦截类
 */
@Service
public class DemoAnnotationService {
    @Action(name="注解式拦截的div操作")
    public void div(){
        System.out.println("=======div========");
        System.out.println("    15/3=5");
        System.out.println("=======end========");
    };
}

3.编写使用方法规则被拦截类

        这种形式比较常见,就是一个普通的类,然后在切面中与切点关联即可。

package com.carson.aop;

import org.springframework.stereotype.Service;

/**
 * 编写使用方法规则被拦截类
 */
@Service
public class DemoMethodService {
    public void add(){
        System.out.println("=========加法==========");
        System.out.println("         3+5=8");
        System.out.println("==========end==========");
    };
}
package com.carson.aop;

import org.springframework.stereotype.Service;

@Service
public class DemoAfterService {
    public void write(int x,int y){
        System.out.println("该方法有两个参数,分别为:"+x+","+y);
    }
}

4.编写切面

         这个切面类中会将以上两种规则都分别关联起来。其中@After、@Before、@Around定义建言,可直接将拦截规则(切点)作为参数。同时,也可以用@PointCut定义拦截规则。另外,符合条件的每一个被拦截处称为连接点(JoinPoint)。

package com.carson.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.stereotype.Component;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

/**
 * 编写切面
 */
@Aspect//通过@Aspect注解声明一个切面
@Component//通过@Component让此切面成为Spring容器管理的Bean。
public class LogAspect {

    @Pointcut("@annotation(com.carson.aop.Action)")//通过@PointCut注解声明切点
    public void annotationPointCut(){};

    @Pointcut(value="execution(* com.carson.aop.DemoAfterService.*(..))")
    public void pointCut(){};

    @After("annotationPointCut()")
    public void after(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        Action action = method.getAnnotation(Action.class);
        System.out.println("注解式拦截,在方法执行之后拦截,"+action.name());//通过反射可获得注解上的属性,然后做日志记录相关的操作
    }



    @Before(value = "execution(* com.carson.aop.DemoMethodService.*(..))")//通过@Before注解声明一个建言,此建言直接使用拦截规则作为参数
    public void before(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        System.out.println("方法规则式拦截在方法执行之前拦截,"+method.getName());
    }



    @After("pointCut()")
    public void around(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        Object[] args = joinPoint.getArgs();
        int ans = 0;
        for(int i=0;i<args.length;i++){
            ans+=(int)args[i];
        }

        System.out.println("在执行"+method.getName()+"之后计算"+method.getName()+"方法中各参数的和为:"+ans);
    }
}

5.编写配置类

package com.carson.aop;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * 配置类
 */

@Configuration
@ComponentScan("com.carson.aop")
@EnableAspectJAutoProxy//使用@EnableAspectJAutoProxy注解开启Spring对AspectJ的支持
public class AopConfig {
}

        以上用配置类来代替xml文件,其中配置类通过一些特定的注解实现了配置需求。

6.编写运行类

package com.carson.aop;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);//读取配置类,正式使用注解开启了Spring对AspectJ的支持
        DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class);

        DemoMethodService demoMethodService = context.getBean(DemoMethodService.class);
        DemoAfterService demoAfterService = context.getBean(DemoAfterService.class);

        demoAnnotationService.div();
        System.out.println("- - - - - - - - - -");
        demoMethodService.add();
        System.out.println("- - - - - - - - - -");
        demoAfterService.write(3,5);
        context.close();
    }
}

运行结果:

一月 09, 2019 9:46:01 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@191beef: startup date [Wed Jan 09 21:46:00 CST 2019]; root of context hierarchy
=======div========
    15/3=5
=======end========
注解式拦截,在方法执行之后拦截,注解式拦截的div操作
- - - - - - - - - -
方法规则式拦截在方法执行之前拦截,add
=========加法==========
         3+5=8
==========end==========
- - - - - - - - - -
一月 09, 2019 9:46:01 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@191beef: startup date [Wed Jan 09 21:46:00 CST 2019]; root of context hierarchy
该方法有两个参数,分别为:3,5
在执行write之后计算write方法中各参数的和为:8

Process finished with exit code 0

        可以看出,基于方法规则拦截方式更易理解,而基于注解拦截能够很好地控制拦截的粒度和获得更丰富的信息。在初学时可以先从基于方法规则拦截方式入手,然后逐步加深理解。

猜你喜欢

转载自blog.csdn.net/carson0408/article/details/86182300
今日推荐