• 后端——框架——切面框架——aop——HelloWorld示例


      本篇演示AOP的Hello World示例,三种方式,aspectJ类,注解方式,spring AOP。

      示例演示在MessageCommunicator的deliver方法执行之前插入一段代码,这里是Authenticator类的authenticate方法,插入的这段代码不是重点,可以直接替换为简单代码,例如System.out.println("come from aop")。

    1、aspectJ类

      实现的步骤如下:

      第一步:编写任意业务模块的类,编写任意方法。原著中为MessageCommunicator类,它只是将方法的参数打印在控制台上。创建对象,运行deliver方法,它只是简单的把参数打印在控制台。

    public class MessageCommunicator {
    
    	/**
    	 * 
    	 * @Title: deliver
    	 * @Description:方法非常简单,将message打印到控制台上
    	 * @param message
    	 */
    	public void deliver(String message) {
    		System.out.println(message);
    	}
    	/**
    	 * 
    	 * @Title: deliver
    	 * @Description 方法非常简单,将Person的名称和message打印在控制台上
    	 * @param person
    	 * @param message
    	 */
    	public void deliver(String person, String message) {
    		System.out.println(person + ":" + message);
    	}
    }
    

      第二步:公共业务模块的代码,这段代码让用户输入两次,两次输入一致即通过,如果为了方便,可以修改authenticate(),输出”check something”。

    public class Authenticator {
    
    	private ThreadLocal<String> authenticatedUser = 
    new ThreadLocal<String>();
    
    	public void authenticate() {
    		if (isAuthenticated()) {
    			return;
    		}
    		String[] userNamePassword = getUserNamePassword();
    		if (!userNamePassword[0].equals(userNamePassword[1])) {
    			System.out.println("User/password didn't match");
    		}
    		authenticatedUser.set(userNamePassword[0]);
    	}
    
    	public boolean isAuthenticated() {
    		return authenticatedUser.get() != null;
    	}
    
    	public String[] getUserNamePassword() {
    		boolean usePrintln = Boolean.getBoolean("ant.run");
    		String[] userNamePassword = new String[2];
    		BufferedReader in = 
    new BufferedReader(new InputStreamReader(System.in));
    		try {
    			if (usePrintln) {
    				System.out.println("Username: ");
    			} else {
    				System.out.print("Username: ");
    			}
    			userNamePassword[0] = in.readLine().trim();
    			if (usePrintln) {
    				System.out.println("Password: ");
    			} else {
    				System.out.print("Password: ");
    			}
    			userNamePassword[1] = in.readLine().trim();
    		} catch (IOException ex) {
    			// ignore... will return array of null strings
    		}
    		return userNamePassword;
    	}
    }
    

      第三步:编写AspectJ,这是重点。它将业务模块和公共模块关联起来。

    public aspect SecurityAspectJ {
    	// 继承Java的语法,可以自定义变量
    	private Authenticator authenticator = new Authenticator();
    	
    	/**
    	 *  
    	 * @Title: secureAccess
    	 * @Description:定义pointcut,只能在AspectJ中定义,在本例为MessageCommunicator的deliver方法
    	 * 格式  pointcut name : join point,本示例中三个部分
    	 * 1.pointcut:关键字
    	 * 2.secureAccess: pointcut的名称,不是必须的
    	 * 3.execution(): 是join point的一种,表示在方法执行之前。在第四章节中将介绍
    	 * 4. * :* 表示不限包名, 
    	 * 5 MessageCommunicator.deliver(..)表示MessageCommunicator的deliver方法,
    	 * 6. .. 表示不限制方法的参数个数和类型
    	 */
    	pointcut secureAccess() : execution(* MessageCommunicator.deliver(..));
    	
    	/**
    	 * 
    	 * @Title: before
    	 * @Description:定义Advice
    	 *       格式  when : pointcut name { // 代码,通常包含公共模块的代码   }
    	 * 1. when:定义AspectJ代码与业务代码的运行时机,有三种类型,before(之前),after(之后),around(环绕)
    	 * 2. pointcut name:这里引用上述的secureAccess
    	 * 3. AspectJ代码:通常包含公共模块的代码,在后续章节中会学到很多的特定上下文。
    	 */
    	before() : secureAccess(){
    		System.out.println("Checking and authenticating user");
    		authenticator.authenticate();
    	}
    }
    

      上述的AspectJ包含pointcut,advice。它的格式,以及每一项的含义都包含在方法注释中。上述的Advice只是其中一种Crosscutting element(切面点),在第二小节会具体介绍切面点。

    2、注解语法

    AspectJ还有另外一种语法,是在普通Java类上添加AOP相关注解。代码如下:

    /**
     * 
     * @File Name: Security.java
     * @Description: SecurityAspectJ的
     * @version 1.0
     * @since JDK 1.8
     */
    @Aspect
    public class Security {
    	// 负责校验功能的类
    	private Authenticator authenticator = new Authenticator();
    
    	@Pointcut("execution (* ch2.MessageCommunicator.deliver(..))")
    	public void secureAccess() {
    	}
    
    	@Before("secureAccess()")
    	public void secure() {
    		System.out.println("Checking and authenticating user");
    		authenticator.authenticate();
    	}
    }
    

      与直接编写AspectJ,主要有以下三点区别:

    1. AspectJ:从public aspect name的语法改变为在@AspectJ注解。
    2. Pointcut:有以下三个变化
      • Pointcut关键字改变为@Pointcut注解
      • Pointcut的名称从自定义名称改变为Java类方法的名称,在上述示例中为secureAccess方法,它方法体是空的。
      • Pointcut中join point这部分的内容没有改变,结构从跟在name的冒号变为@Pointcut注解的value属性。

      3.Advice:有以下两个变化

      • Advice中的时机before改变为@Before注解
      • Pointcut的name改变为@Before注解的value属性。

    3、SpringAOP方式

    使用spring方式实现相同功能的步骤如下:

    1. 编写业务代码,公共模块代码,编写Aspect,这些都不变
    2. 将业务类,公共类,Aspect类注入到容器中。
    3. 在配置文件中引入aop schema,添加<aop:aspectj-autoproxy>配置。

    配置如下:

    <aop:aspectj-autoproxy/>
    <!-- 配置公共业务模块 -->
    <bean id="coreConcern" class="ch2.MessageCommunicator"/>
    <!-- 配置Aspect -->
    <bean id="securityAspect" class="ch2.Security"/>
    

      注解方式,SpringAOP方式在实际工作场景中较多。

  • 相关阅读:
    acceptorThreadCount
    spring boot tomcat 线程数 修改初始线程数 统计性能 每百次请求耗时
    java 获取当前进程id 线程id
    Linux操作系统中打开文件数量的查看方法
    java.io.IOException: Too many open files
    随机采样 算法
    Spring Boot
    您好,python的请求es的http库是urllib3, 一个请求到贵司的es节点,想了解下,中间有哪些网关啊?冒昧推测,贵司的部分公共网关与python-urllib3的对接存在异常?
    运行状态:锁定中(实例空间满自动锁)
    。。。。。。不带http https : 不报错 spring boot elasticsearch rest
  • 原文地址:https://www.cnblogs.com/rain144576/p/14708731.html
Copyright © 2020-2023  润新知