Spring系列之AOP

什么是AOP?

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于将核心关注点和横切关注点分离开来。

为什么要将这两种进行分离呢?或者说这样做有什么好处?

比如一个登陆功能,你可能需要在用户登陆前后进行权限校验,当用户登录进来购买物品时,也需要进行校验。当系统非常地庞大时,系统中进行权限验证的代码是非常多和散乱的,我们就想能不能将这些权限校验、日志记录等非业务逻辑功能的部分独立拆分开,并且在系统运行时需要的地方(连接点)进行动态插入运行,不需要的时候就不理,因此AOP就起作用了!


AOP中的基本概念

已经大致了解了AOP是个什么东西了,接下来了解一下AOP 的几个基本概念:

  • 切面(Aspect)

切面是切点和通知的集合,一般单独作为一个类。通知和切点共同定义了关于切面的全部内容,它是什么时候,在何时和何处完成功能。

  • 连接点(Join point)

被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

  • 切点(Pointcut)

对连接点进行拦截的定义,指定一个通知将被引发的一系列连接点的集合。

  • 通知(Adivce)

在特定的连接点,AOP框架执行的动作。
通知有5种类型:

  1. Before: 在方法被调用之前调用
  2. After: 在方法完成后调用通知,无论方法是否执行成功
  3. After-returning: 在方法成功执行之后调用通知
  4. After-throwing: 在方法抛出异常后调用通知
  5. Around: 通环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知
  • 引入(Introduction)

添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。

  • 织入(Weaving)

组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。


Spring中的AOP

AOP思想的实现一般都是基于代理模式,在JAVA中一般采用JDK动态代理模式,但是我们都知道,JDK动态代理模式只能代理接口,如果要代理类那么就不行了。因此,Spring AOP 会这样子来进行切换,因为Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理,当你的真实对象有实现接口时,Spring AOP会默认采用JDK动态代理,否则采用cglib代理。

  1. 默认使用JDK动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
  2. 当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

接下来就是实现了:

定义接口(连接点)

package com.xm.aop;

public interface Action {
	
	//登陆
	public void login();
	
	//购买
	public void buy();
	
}

接口文件实现类,这是代理模式中真正的被代理人

package com.xm.aop;

public class ActionImpl implements Action {

	public void login() {
		
		System.err.println("上线!!!!");
		
	}

	public void buy() {
		
		System.err.println("购买中!!!!");
		
	}
}

切面

package com.xm.aop;

 /**
  * 权限
  */
public class Permission { 
  /**
   * 登录校验
   */
	public void beforeLogin() {
		System.err.println("开始校验······");
		
	}
	
	/**
	 * 校验之后做一些处理(无论是否成功都做处理)
	 */
	public void handle() {		
	    System.err.println("正在处理······");
	}
	
}

然后是aop.xml配置文件

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="ActionImpl1" class="com.xm.aop.Action1" />
        <bean id="ActionImpl2" class="com.xm.aop.Action2" />
        <bean id="Permission" class="com.xm.aop.Permission" />
        
        <aop:config>
        <!-- 定义一个切面-->
            <aop:aspect id="permission" ref="Permission">
            	<!-- 定义切点 ,后面表示包括该接口中定义的所有方法都会被执行-->
                <aop:pointcut id="point" expression="execution(*com.xm.aop.Action.*(..))" />
                <!-- 定义通知 -->
                <aop:before method="beforeLogin" pointcut-ref="point" />
                <aop:after method="handle" pointcut-ref="point" />
            </aop:aspect>
        </aop:config>
</beans>

最后测试

public class Test {	
	public static void main(String[] args) {
	
		ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");	  
		
				Action aciton1 = (Action)ctx.getBean("ActionImpl1");
				Action action2 = (Action)ctx.getBean("ActionImpl2");
				
				aciton1.login();
				aciton1.buy();
								
				System.err.println("--------------------");
															
				aciton2.login();
				aciton2.buy();			
	}
}

结果如下

开始校验······
上线!!!!
正在处理······
开始校验······
购买中!!!!
正在处理······
--------------------
开始校验······
上线!!!!
正在处理······
开始校验······
购买中!!!!
正在处理······

上面是xml,还可以通过注解方式

首先在aop.xml中加入

<!-- 开启注解扫描 -->
<context:component-scan base-package="com.xm.aop"></context:component-scan>

<!--开启注解扫描-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

实体类加上 @Component

然后是切面类,就大功告成了,很简单

package com.xm.aop;

 /**
  * 权限
  */
@Component // 加入IOC容器
@Aspect
public class Permission { 

    @Pointcut("execution(*com.xm.aop.Action.*(..))")//切入点
    public  void pointCut(){
    }
  
  /**
   * 登录校验
   */
    @Before("pointCut()")
	public void beforeLogin() {
		System.err.println("开始校验······");
		
	}
	
	/**
	 * 校验之后做一些处理(无论是否成功都做处理)
	 */
	@After("pointCut()")
	public void handle() {		
	    System.err.println("正在处理······");
	}
	
}

以上就是AOP的简单实现,码了这么久,其实只是入门而已,之后还要去进行更深入的研究,加油~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值