后端——框架——切面框架——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方式在实际工作场景中较多。

原文地址:https://www.cnblogs.com/rain144576/p/14708731.html