AOP概述

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

AOP的基本概念

(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

AOP的实现方式

通知类型

说明

前置通知(MethodBeforeAdvice)

目标方法执行之前调用

后置通知(AfterReturingAdvice)

目标方法执行之后调用

环绕通知(MethodInterceptor)

目标方法执行前后都会调用方法,且能增强结果

异常通知(ThrowsAdvice)

目标方法出现异常调用

基于Schema-based方式实现

前置通知
1、创建目标接口和实现类

/**
 * 定义公共接口
 * @author 叶小陌
 *
 */
public interface UserService {
	public void say(String msg);
	public String doSome(String msg);
}
/**
 * 实现类
 * @author 叶小陌
 */
public class UserServiceImpl implements UserService {

	@Override
	public void say(String msg) {
		// TODO Auto-generated method stub

		System.out.println("say" +msg);
	}
	
	@Override
	public String doSome(String msg) {
		System.out.println("dosome" + msg);
		return "hello";
	}
}

2、定义切面类

/**
 * 前置通知
 * @author 叶小陌
 *
 */
public class MyBeforeAdvice implements MethodBeforeAdvice {

	/**
	 * method	目标方法
	 * arg1		目标方法参数列表
	 * target	目标对象
	 */
	@Override
	public void before(Method method, Object[] arg1, Object target) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("前置通知的before方法执行了--------");	
	}
}

3、配置文件中的配置

<?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:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

	<!-- 开启扫描 -->
	<context:component-scan base-package="com.sxt.advice.*"/>
	<!-- 配置目标对象 -->
	<bean class="com.sxt.advice.impl.UserServiceImpl" id="userService"/>
	<!-- 配置前置通知 -->
	<bean class="com.sxt.advice.aop.MyBeforeAdvice" id="myBeforeAdvice"/>
	<!-- 配置代理类 -->
	<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
		<!-- 设置注入方式设置 -->
		<property name="target" ref="userService"></property>
		<!-- 配置接口 -->
		<property name="interfaces" value="com.sxt.advice.UserService"/>
		<!-- 配置通知类型 -->
		<property name="interceptorNames">
			<list>
				<!-- 配置前置通知 -->
				<value>myBeforeAdvice</value>
			</list>		
		</property>
	</bean>
</beans>

4、测试类

public class Main {

	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService bean = ac.getBean("proxyFactoryBean", UserService.class);
		System.out.println(bean.doSome("hello"));
		bean.say("aaa");
	}
}

后置通知:
环绕通知:
异常通知:
案例如下:

/**
 * 后置通知:
 * @author 叶小陌
 *
 */
public class MyAfterReturningAdvice implements AfterReturningAdvice {

	@Override
	public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
		// TODO Auto-generated method stub

		System.out.println("后置通知执行了-----------");
	}
}

/**
 * 环绕通知
 * @author 叶小陌
 *
 */
public class MyMethodInterceptor implements MethodInterceptor{

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("环绕通知------1-----");
		Object res = invocation.proceed();
		if (res != null) {
			//增强返回结果
			res = ((String)res).toUpperCase();
		}
		System.out.println("环绕通知------2----");
		return null;
	}
}

/**
 * 异常通知
 * @author 叶小陌
 *
 */
public class MyThrowsAdvice implements ThrowsAdvice{

	public void afterThrowing(Exception e){
		System.out.println("异常发生了---------");
	}
}

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:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

	<!-- 开启扫描 -->
	<context:component-scan base-package="com.sxt.advice.*"/>
	<!-- 配置目标对象 -->
	<bean class="com.sxt.advice.impl.UserServiceImpl" id="userService"/>
	<!-- 配置后置通知 -->
	<!-- <bean class="com.sxt.advice.aop.MyAfterReturningAdvice" id="myAfterReturningAdvice"/> -->
	<!-- 配置前置通知 -->
	<bean class="com.sxt.advice.aop.MyBeforeAdvice" id="myBeforeAdvice"/>
	<!-- 配置环绕通知 -->
	<bean class="com.sxt.advice.aop.MyMethodInterceptor" id="myMethodInterceptor"/>
	<!-- 配置异常通知 -->
	<bean class="com.sxt.advice.aop.MyThrowsAdvice" id="myThrowsAdvice"/>	
	<!-- 配置代理类 -->
	<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
		<!-- 设置注入方式设置 -->
		<property name="target" ref="userService"></property>
		<!-- 配置接口 -->
		<property name="interfaces" value="com.sxt.advice.UserService"/>
		<!-- 配置通知类型 -->
		<property name="interceptorNames">
			<list>
				<!-- 配置后置通知 -->
				<!-- <value>myAfterReturningAdvice</value> -->
				<!-- 配置前置对象 -->
				<!-- <value>myBeforeAdvice</value> -->
				<!-- 配置环绕通知 -->
				<!-- <value>myMethodInterceptor</value> -->
				<!-- 配置异常通知 -->
				<value>myThrowsAdvice</value>
			</list>		
		</property>
	</bean>
</beans>