AOP之@AspectJ技术

1、AspectJ技术

因为在xml配置aop过程中太过繁琐,aopalliance 中出现了一种AspectJ技术。

2、 Spring AOP支持的AspectJ切入点指示符

切入点指示符用来指示切入点表达式目的,,在Spring AOP中目前只有执行方法这一个连接点,Spring AOP支持的AspectJ切入点指示符如下:

execution:用于匹配方法执行的连接点;
within:用于匹配指定类型内的方法执行;
this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
@within:用于匹配所以持有指定注解类型内的方法;
@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
@args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
@annotation:用于匹配当前执行方法持有指定注解的方法;
bean:Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法;
reference pointcut:表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持。

3、类型匹配语法

首先让我们来了解下AspectJ类型匹配的通配符:

*:匹配任何数量字符;
…:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
+:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

代码:
java.lang.String    匹配String类型;  
java.*.String       匹配java包下的任何“一级子包”下的String类型;  
如匹配java.lang.String,但不匹配java.lang.ss.String  
java..*            匹配java包及任何子包下的任何类型;  
                  如匹配java.lang.String、java.lang.annotation.Annotation  
java.lang.*ing      匹配任何java.lang包下的以ing结尾的类型;  
java.lang.Number+  匹配java.lang包下的任何Number的自类型;  
                   如匹配java.lang.Integer,也匹配java.math.BigInteger 

4、组合切入点表达式

AspectJ使用 且(&&)、或(||)、非(!)来组合切入点表达式。
在Schema风格下,由于在XML中使用“&&”需要使用转义字符“&&”来代替之,所以很不方便,因此Spring ASP 提供了and、or、not来代替&&、||、!。

5、切入点使用示例

execution:使用“execution(方法表达式)”匹配方法执行;
模式 描述
public * *(…) 任何公共方法的执行
* cn.javass…IPointcutService.*() cn.javass包及所有子包下IPointcutService接口中的任何无参方法
* cn.javass….(…) cn.javass包及所有子包下任何类的任何方法

6、AspectJ技术实例

  • 通过注解配置切点(哪个方法需要被入侵)和通知(黑客)

  • 自动生产代理对象

1)创建AppConfig.java

package com.lq.aspect;

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

@Configuration // 标示为配置类 相当于xml文件
//扫描指定包下包含@Component注解的类,将这个类加入spring bean工程
@ComponentScan(value = {
    
     "com.lq.aspect", "com.lq.dao" })
@EnableAspectJAutoProxy // 启动aspectJ注解aop
public class AppConfig {
    
    

}
  1. 创建@Aspect 切面类
package com.lq.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogAspect {
    
    

	/*
	 * 定义切点----需要增强的方法
	 * 
	 */

	@Pointcut("execution(public int com.lq.dao.UserDapImpl.add(..))")
	public void pointCut() {
    
    
	}

	// 环绕通知(循环通知/增强(黑客))

	@Around("pointCut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
		System.out.println("1.鉴权");
		// 调用目标方法

		Object[] args = joinPoint.getArgs();
		args[0] = 22;
		args[1] = 22;
		Object result = joinPoint.proceed();

		System.out.println("2.日志留痕");
		return result;

	}
}

3)实体类

package com.lq.dao;

import org.springframework.stereotype.Component;

@Component
public class UserDapImpl {
    
    

	public int add(int a,int b) {
    
    
		System.out.println("调用【未实现接口的】UserDaoImpl的add方法");
		return a+b;
	}
}

  1. 测试
package com.lq.proxy;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.lq.aspect.AppConfig;
import com.lq.dao.UserDapImpl;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class AspectJTest {
    
    

	@Autowired
	UserDapImpl userDap;

	@Test
	public void testAdd() {
    
    
		System.out.println(userDap.add(11, 22));
	}

}

  1. 测试结果为:
九月 29, 2020 10:40:17 下午 org.springframework.test.context.support.AbstractTestContextBootstrapper getDefaultTestExecutionListenerClassNames
信息: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
九月 29, 2020 10:40:17 下午 org.springframework.test.context.support.AbstractTestContextBootstrapper getTestExecutionListeners
信息: Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@13fee20c, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@4e04a765, org.springframework.test.context.support.DirtiesContextTestExecutionListener@783e6358]
九月 29, 2020 10:40:18 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.GenericApplicationContext@100fc185: startup date [Tue Sep 29 22:40:18 CST 2020]; root of context hierarchy
1.鉴权
调用【未实现接口的】UserDaoImpl的add方法
2.日志留痕
33

猜你喜欢

转载自blog.csdn.net/weixin_46822085/article/details/108876782