Spring Aop 面向切面编程

 

1 Aop是什么?

注明(此段话引自):https://blog.csdn.net/when_less_is_more/article/details/78175891?utm_source=copy

Aspect Oriented Programming  面向切面编程。解耦是程序员编码开发过程中一直追求的。AOP也是为了解耦所诞生。

具体思想是:定义一个切面,在切面的纵向定义处理方法,处理完成之后,回到横向业务流。

AOP 在Spring框架中被作为核心组成部分之一,的确Spring将AOP发挥到很强大的功能。最常见的就是事务控制。工作之余,对于使用的工具,不免需要了解其所以然。学习了一下,写了些程序帮助理解。

 

 

2 spring AOP 可以用来干什么?

1 防止过多代码沉积 (比如记录日志等,再也不需要每个代码里面 添加记录日志代码)

2 统一组织 管理代码 拦截某些方法执行前后,做一些操作(如关闭 流,操作事务,记录日志等等), 不影响原程序。

3 实现方式

  1. 注解实现

通知:

就是你想要用到的功能,也就是上面说的 安全,事物,日志等。自己 先定义好,然后在想用的地方用一下。

连接点:

就是spring允许你使用通知的地方,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点.其他如aspectJ还可以让你在构造器或属性注入时都行,不过那不是咱关注的,只要记住,和方法有关的前前后后(抛出异常),都是连接点。

切面:

可以是具体的一个类

切点:

 声明需要切入方法的定义 ,此方法不会执行    

5种类型:

  • Before 某方法调用之前发出通知。
  • After 某方法完成之后发出通知,不考虑方法运行的结果。
  • After-returning 将通知放置在被通知的方法成功执行之后。
  • After-throwing 将通知放置在被通知的方法抛出异常之后。
  • Around 通知包裹在被通知的方法的周围,在方法调用之前和之后发出通知。

maven依赖:

         <dependencies>
        <!-- spring的依赖包 -->
        
         <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.3.1.RELEASE</version>
            <type>jar</type>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.6.9</version>
</dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.0.RELEASE</version>
</dependency>
    
    <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/springframework/spring-orm -->
<dependency>
    <groupId>springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>1.2.6</version>
</dependency>

service:

public interface UseSercvice {


	public String say(String name);
}

service 实现类:

@Service
public class UseSercviceImpl  implements UseSercvice{

	public void say() {
		 
		System.out.println("hahhaha...");
		
	}

	public String say(String name) {
		System.out.println(name);
		return name;
	}

}

切面类:


@Component

@Aspect  //声名切面

public class AspectTest {

	//声名切点 : 声明需要切入方法的定义 ,此方法不会执行    
	@Pointcut("execution(* com.udeam.Service.*.*(..))")    // 正则表达
	public void pointVoid() {	
		
		System.out.println("------切点-----");
	}
	
	 
	 @Before("pointVoid()")
	public void doBefor(JoinPoint joinpoint) {
		 
		//获取方法名
		 System.out.println("前置通知:----------切入点方法名:"+joinpoint.getSignature().getName());  
		
		
	}
	  
    
	 @After("pointVoid()")  
	public void doAfter(JoinPoint joinpoint) {
		
		//获取方法名
		 System.out.println("后置通知:-----------切入点方法名:"+joinpoint.getSignature().getName());  
		
	}
	
	 @AfterReturning(value="pointVoid()",returning="result") // 方法正常结束后执行的代码   返回通知是可以访问到方法的返回值的 
	public void afterReturning(JoinPoint joinPoint, Object result){
		String methodName = joinPoint.getSignature().getName();  
        System.out.println("返回通知: method " + methodName + " 返回值: " + result);  
	}
	
	
	
	 @Around("pointVoid()")  //之前之后都会执行
	 public Object around(ProceedingJoinPoint   pJoinPoint){
		 Object[] args = pJoinPoint.getArgs();//获取参数
		 String name = pJoinPoint.getTarget().getClass().getName();//获取类名
		 System.out.println("环绕开始。。。");
		 System.out.println("参数:" +  args.toString() + "  名字" + name);
		 Object proceed =null;
		 try {
			// 控制切入点方法的执行 
			 proceed = pJoinPoint.proceed();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			 System.out.println("环绕完成。。。。");
		}
		 return proceed;
	 }
	 
	 
	 @AfterThrowing("pointVoid()")
	 public void afterThrowing() {
		 System.out.println("异常执行。。。");
	 }
}

 

spring配置 文件 

约束

            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd "

		<!-- 注解扫描 -->
	 <context:component-scan base-package="com.udeam.*"/>
		<!-- aop 注解实现  自动代理-->
	 	 <aop:aspectj-autoproxy />

测试:

	//加载springContext 配置文件
		
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
		UseSercvice useSercvice = (UseSercvice) context.getBean("useSercviceImpl");
		useSercvice.say("zs");
		

结果:

 

可能 出现的问题:

ClassNotFoundException:org.aspectj.weaver.reflect.ReflectionWorld $ ReflectionWorldExceptionClassNotFoundException:org.aspectj.weaver.reflect.ReflectionWorld $ ReflectionWorldException

缺少下面依赖:

 
    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>

 2 xml实现

切面类


public class AspectTest2 {

	 
	public void pointVoid() {
		
		System.out.println("------切点不执行-----");
	}
	
	 
	 
	public void doBefor() {
		
		 System.out.println("前置通知:----------");  
		
	}
	  
	public void doAfter() {
		
		 System.out.println("后置通知-------------");  
		
	}
	
	public void doAround(ProceedingJoinPoint point) {
		
		System.out.println("环绕通知前-------------");  
		try {
			point.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		 System.out.println("环绕通知后-------------");  
		
	}

}

 

xml配置

	<!-- 切面 -->
	<bean id="aspect"  class="com.udeam.aspect.AspectTest2" />

	
	<!-- xml配置aop -->
		<aop:config>
		<!-- 定义切面 -->
			<aop:aspect  ref="aspect">
				<!-- 切点 -->
				 <aop:pointcut id="allManagerMethod" expression="execution(* com.udeam.Service.*.*(..))"></aop:pointcut>
				 <!--通知--> 
				 <aop:before method="doBefor" pointcut-ref="allManagerMethod"></aop:before>
				 <aop:after  method="doAfter" pointcut-ref="allManagerMethod"></aop:after>
				 <aop:around method="doAround" pointcut-ref="allManagerMethod"></aop:around>
			</aop:aspect>
		</aop:config>