Spring AOP基本原理及AOP两种配置方式初体验

在spring中,除了IOC(控制反转)之外,还有一个重要特性就是面向切面编程。

AOP=面向切面的编程=Aspect Oriented Programming

实现基本原理关键词:动态代理拓展程序功能、申明式事务管理

1.Spring AOP 的一些术语:
(1)切面(Aspect)
  要增加什么功能?例如事务管理,日志管理,权限管理,异常处理

(2)连接点(Joinpoint)
  哪个类的哪个方法上增加功能

(3) 通知(Advice)
    加在方法的什么位置?前面?后面?产生异常时?环绕(前后都添加)??

(4)切入点(Pointcut)
  给连接点命名,便于在多处使用

(5)目标对象(Target Object)
  被代理对象,自己的功能不够强大,要通过aop加强

(6)AOP代理
  功能已经加强的那个对象

(7)织入(weaving)
  把新功能和本身的功能组织在一起执行


2.注解配置AOP的实现

这里还是结合一个注册案例来解释AOP基本注解配置。

功能描述:在点击注册之后,将用户名和密码存入数据库中。现在想通过AOP实现在这个add方法调用之前控制台输出“方法开始”,在方法调用结束后输出“方法结束”。这里不在DAO实现类中添加这个功能,而是注解配置AOP来实现

(1)要想添加日志功能先把日志功能在类中写出来。新建一个包 net.xinqushi.aop ,新建一个Log类
类中写两个方法,表示方法调用之前输出日志,调用之后输出日志


把这个类变成一个切面类,表示这个类是添加到别的地方作为一个切面  注解:@Aspect

这个类也要初始化为一个对象  注解:@Component(value=”log”)   这里要在配置文件中把这个包加入到初始化为对象时搜索到包中。

<context:component-scan base-package=”net.xinqushi.dao.impl,net.xinqushi.service.impl,net.xinqushi.aop”/>

(2)现在考虑打印日志的功能应该加在哪个类的哪个方法上?是加在方法执行之前,还是之后?


在之前,这里就在方法之前添加注解
@Before(“execution(public void net.xinqushi.service.impl.save(net.xinqushi.model.User))”)

这里注意@Before一定要选 org.aspectj.lang.annotation.Aspect包下的

在之后,这里就结束方法之前添加注解
@AfterRunning(“execution(public void net.xinqushi.service.impl.save(net.xinqushi.model.User))”)


(3)修改spring的配置文件  在applicationContex.xml文件中添加配置

添加命名空间  xmlns:aop=”http://www.springframework.org/schema/aop”

添加xsd xml格式约束文件:
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd

使配置文件支持aop注解
<aop:aspectj-autoproxy/>


3.这里再介绍一下优化注解配置的通配符法

(1)joinpoint语法:用一些通配符来定义在哪些类和方法上增加aop功能。

  语法:
  1).execution(public * *(..))
    所有public方法 
 
  2).execution(* set*(..))
    所有以set作为方法名开头的方法

  3).exuection(* com.xzy.service.AccountService.*(..))
   com.xzy.service.AccountService类中的所有方法

  4).execution(* com.xyz.service.*.*(..))
   com.xyz.service包中所有类的所有方法

  5).execution(* com.xyz.service..*.*(..))
   com.xyz.service包及子包下的所有类的所有方法

(2)pointcut:给joinpoint取个名字。  使程序更加整洁
  @pointcut(value=”execution( * com.xzy.*.*(..))”)
  public void businessService(){}

(3)advice 

 @Before
 @AfterReturning
 @AfterThrowing
 @After(finally)
 @Around

(4)JoinPoint jp  可以为打印日志的before方法和end方法传进去一个参数

这个参数就可以get到很多关于连接点的信息。这里可以试着获得方法签名

这里导入的也是import org.aspectj.lang.JoinPoint;


Log.java

package net.xinqushi.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component(value="log")
public class Log {
	@Pointcut(value="execution(* net.xinqushi.service.impl.*.*(..))")
	public void myPoint(){}
	@Before("myPoint()")
	//方法执行之前输出
	public void mybefore(JoinPoint jp){
		System.out.println(jp.getSignature() +"方法开始执行");
	}
	@AfterReturning("myPoint()")
	//方法执行完后输出
	public void myafter(JoinPoint jp){
		System.out.println(jp.getSignature()+"方法执行结束");
	}
}

5.AOP xml配置方式

(1)先把Log.java中的注解配置注释掉,这里保留@Component(value=”log”)。因为xml方式也是要将这个类初始化为一个对象,当然这里也可以采用xml方式去初始化这个类。(前边博客有讲)


(2)在配置文件中添加aop标签的配置

这里之前在注解配置中引入的命名空间和xsd约束文件都是要保留的


<?xml version="1.0" encoding="UTF-8"?>    
<beans xmlns="http://www.springframework.org/schema/beans"    
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xmlns:p="http://www.springframework.org/schema/p"  
    xmlns:aop="http://www.springframework.org/schema/aop"   
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:jee="http://www.springframework.org/schema/jee"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="    
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
        http://www.springframework.org/schema/mvc   http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd  
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
		<context:annotation-config></context:annotation-config>
	<context:component-scan base-package="net.xinqushi.dao.impl,net.xinqushi.service.impl,net.xinqushi.aop"/>
	<aop:config>
		<aop:aspect ref="log">
		<aop:pointcut 
			expression="execution(* net.xinqushi.service.impl.*.*(..))" id="mypt"/>
		<aop:before method="mybefore" pointcut-ref="mypt"/>
		<aop:after method="myafter" pointcut-ref="mypt"/>
		</aop:aspect>
	</aop:config>
	<!-- 注解配置AOP才会用到的 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

其中这段注解大概的意思就是先把log设置为一个切面,然后设置切入点,再根据Log类中的两个打印日志的方法设置其pointcut-ref属性

	<aop:config>
		<aop:aspect ref="log">
		<aop:pointcut 
			expression="execution(* net.xinqushi.service.impl.*.*(..))" id="mypt"/>
		<aop:before method="mybefore" pointcut-ref="mypt"/>
		<aop:after method="myafter" pointcut-ref="mypt"/>
		</aop:aspect>
	</aop:config>

    原文作者:AOP
    原文地址: https://blog.csdn.net/zlj1217/article/details/60882718
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞