Spring学习-Spring07-AOP之通知

Spring07-AOP

切面
切面泛指交叉业务逻辑。比如事务处理、日志处理就可以理解为切面。常用的切面
有通知与顾问。实际就是对主业务逻辑的一种增强。

通知(Advice)
通知是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。
通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之
后执行等。通知类型不同,切入时间不同。

常用的通知分类
前置通知 MethodBeforeAdvice
后置通知 AfterReturningAdvice
环绕通知MethodInterceptor
异常处理通知ThrowsAdvice

Spring对AOP的实现

Spring对AOP的实现
基于Schema-based方式
AspectJ的实现方式
1. 通知的用法
  • 定义通知类
//切面:前置通知
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
	/**
	 * method:目标方法
	 * args:目标方法参数列表
	 * target:目标对象
	 */
	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {

		System.out.println("前置方法的before()方法执行!");
	}

	

}

//切面:后置通知
public class MyAfterReturningAdvice implements AfterReturningAdvice{

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		
		System.out.println("后置通知的afterReturning()方法执行!returnValue: " + returnValue);
		if (returnValue != null) {
			
			System.out.println(((String)returnValue).toUpperCase());
		}
	}
	
}

//切面:环绕通知
public class MyMethodInterceptor implements MethodInterceptor {

	/**
	 * invocation: 方法调用器
	 */
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("环绕通知:目标方法执行之前!");
		//调用执行目标方法
		Object result = invocation.proceed();
		if (result != null) {
			
			result = ((String)result).toUpperCase();
		}
		System.out.println("环绕通知:目标方法执行之后!");
		
		return result;
	}

}

//切面:异常通知(发生异常,目标方法不再执行)
public class MyThrowsAdvice implements ThrowsAdvice {
	public void afterThrowing(Exception ex) {
		System.out.println("异常通知执行!" + ex);
	}	
}
  • 定义目标类
package com.caorui.service;

public interface SomeService {
	void doSome();	
	String doOther();
}
package com.caorui.service.impl;

import com.caorui.service.SomeService;

public class SomeServiceImpl implements SomeService {

	public SomeServiceImpl() {
		System.out.println("SomeServiceImpl.SomeServiceImpl()");
	}
	@Override
	public void doSome() {
//		System.out.println("SomeServiceImpl.doSome()");
		System.out.println("SomeServiceImpl.doSome()" + 1/0);
	}
	@Override
	public String doOther() {
		System.out.println("SomeServiceImpl.doOther()");
		return "love";
	}

}
  • 注册目标类,注册通知切面,注册代理工厂Bean类对象ProxyFactoryBean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 注册目标类 -->
	<!-- bean的定义:以下配置相当于SomeService service = new SomeServiceImpl(); id相当于service这个引用 -->
	<bean id="someServiceImpl" class="com.caorui.service.impl.SomeServiceImpl"></bean>
	<!-- 注册切面,前置通知 -->
	<bean id="myMethodBeforeAdvice" class="com.caorui.aspects.MyMethodBeforeAdvice"></bean>
	<!-- 注册切面,后置通知 -->
	<bean id="myAfterReturningAdvice" class="com.caorui.aspects.MyAfterReturningAdvice"></bean>
	<!-- 注册切面,环绕通知 -->
	<bean id="myMethodInterceptor" class="com.caorui.aspects.MyMethodInterceptor"></bean>
	<!-- 注册切面,异常通知 -->
	<bean id="myThrowsAdvice" class="com.caorui.aspects.MyThrowsAdvice"></bean>
	<!-- 注册代理 -->
	<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 指定目标对象 -->
		<property name="target" ref="someServiceImpl"></property>
		<!-- 指定目标类实现的所有接口 -->
		<property name="interfaces" value="com.caorui.service.SomeService"></property>
		<!-- 指定切面 -->
		<property name="interceptorNames" value="myThrowsAdvice"></property>
	</bean>
</beans>

注意:针对interceptorNames、interfaces后面为什么使用value?

  1. proxyInterfaces(底层传值类型Class[])通过标签array可以设置多个值,只有一个值时,value=""
    底层:
    java proxyInterfaces-ProxyFactoryBean.setProxyInterfaces(Class[] proxyInterfaces) //.xml文件中给不了class,只能给全限定名
  2. target(底层传值类型Object target)
    底层:
    java target-Advised.setTarget(Object object)//Object所以使用ref传对象
  3. interceptorNames:通知切面类的名称,类型是String[],如果设置一个值value=""
    底层:
    java interceptorNames-ProxyFactoryBean.setInterceptorNames(String[] interceptorNames)
    所以interceptorNames后面使用value传值,如果是多个值,则加一个array或者list。
  • 客户端访问动态代理对象
package com.caorui.test;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

import com.caorui.service.SomeService;
import com.caorui.service.impl.SomeServiceImpl;

public class SomeTest {

	@Test
	public void testSome01() {
		//创建容器对象,ApplicationContext初始化时,所有容器中beans创建完毕
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		SomeService service = ac.getBean("proxyFactoryBean", SomeService.class);
		service.doSome();
		String result = service.doOther();
		System.out.println(result);
		
		
	}	

}

发布了8 篇原创文章 · 获赞 0 · 访问量 166

猜你喜欢

转载自blog.csdn.net/Fu_si/article/details/104524924