spring FrameWork 第六章:AOP代理的五大通知:前置,后置通知

14 篇文章 0 订阅

 

 

需要jar包

接口

package com.aop;

public interface UserDao {
	public void addUser(String id, String name);
}

实现类

package com.aop;

public class UserDaoImpl implements UserDao {

	@Override
	public void addUser(String id, String name) {
		System.out.println("==============addUser方法正在逻辑执行============");
	}

}

一.先来个前置通知的切面类:需要实现:

需要注意的是:

arg0:表示public abstract void com.aop.UserDao.addUser(java.lang.String,java.lang.String) 方法

arg1:  表示方法类型

arg2 : 表示 com.aop.UserDaoImpl 代理的实现类

package com.aop;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class LogBeforeAspect implements MethodBeforeAdvice{

	@Override
	public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
		// TODO Auto-generated method stub 
		System.out.println("arg0:"+arg0  );
		System.out.println("----arg1 length"+arg1.length);
		System.out.println( "----arg2:"+ arg2);
		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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	 <!-- target object -->
	 <bean id="userDao" class="com.aop.UserDaoImpl"/>
	 
	 <!-- 切面 :环绕通知-->
	 <bean id="logAspect" class="com.aop.LogAspect"/>
	 <!-- 前置通知 -->
	 <bean id="logBeforeAspect" class="com.aop.LogBeforeAspect"/>

	 
	 <!-- aop的代理:  ProxyFactoryBean -->
	 <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
	 	<!-- 需要代理哪些接口? -->
	 	<property name="proxyInterfaces" value="com.aop.UserDao"/>
	 	<!-- 目标对象? ref 表示引用类型 -->
	 	<property name="target" ref="userDao"/>
	 	<!-- 拦截器的名字: 也就是切面类的名字 ? -->
	 	<!-- <property name="interceptorNames" value="logAspect"/> -->
	 	<property name="interceptorNames" value="logBeforeAspect"/>
	 	<!-- 代理类是不是接口,false表示JDK代理 -->
	 	<property name="proxyTargetClass" value="false"/>
	 </bean> 
	 
</beans>

只需要改动一行:    <property name="interceptorNames" value="logBeforeAspect"/> 改动切面

测试下:

package com.aop;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

class TestUserDao {

	@Test
	void testAddUser() {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserDao userDao = context.getBean("userDaoProxy", UserDao.class);
		userDao.addUser("zhh", "zqw");
	}

}

结果:

 

二.后置通知:需要实现AfterReturningAdvice接口

package com.aop;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class LogAfterAspect implements AfterReturningAdvice{

	@Override
	public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
		// TODO Auto-generated method stub
		
		System.out.println("arg0:"+arg0  );
		System.out.println("arg1:"+arg1);
		System.out.println("arg2 length:"+arg2.length);
		System.out.println("arg3:"+arg3);
        System.out.print("-------------后置通知执行---------");
	}

}

配置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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	 <!-- target object -->
	 <bean id="userDao" class="com.aop.UserDaoImpl"/>
	 
	 <!-- 切面 :环绕通知-->
	 <bean id="logAspect" class="com.aop.LogAspect"/>
	 <!-- 前置通知 -->
	 <bean id="logBeforeAspect" class="com.aop.LogBeforeAspect"/>
	 <!-- 后置通知 -->
	  <bean id="logAfterAspect" class="com.aop.LogAfterAspect"/>

	 
	 <!-- aop的代理:  ProxyFactoryBean -->
	 <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
	 	<!-- 需要代理哪些接口? -->
	 	<property name="proxyInterfaces" value="com.aop.UserDao"/>
	 	<!-- 目标对象? ref 表示引用类型 -->
	 	<property name="target" ref="userDao"/>
	 	<!-- 拦截器的名字: 也就是切面类的名字 ? -->
	 	<!-- <property name="interceptorNames" value="logAspect"/> -->
	 	<!-- 	<property name="interceptorNames" value="logBeforeAspect"/> -->
	 	<property name="interceptorNames" value="logAfterAspect"/>
	 	<!-- 代理类是不是接口,false表示JDK代理 -->
	 	<property name="proxyTargetClass" value="false"/>
	 </bean> 
	 
</beans>

 

测试效果: 是先执行addUser()方法后执行后置通知

 

第三:异常通知(ThrowsAdvice) 

需要注意的是没有重写方法,而是和前置方法有点像。需要Method arg0, Object[] arg1, Object arg2, Throwable error 等参数,多了个Throwable参数

package com.aop;

import java.lang.reflect.Method;

import org.springframework.aop.ThrowsAdvice;

public class LogThrowingAspect implements ThrowsAdvice {
	public void afterThrowing(Method arg0, Object[] arg1, Object arg2, Throwable error) {
		System.out.print("--------异常通知:");
		System.out.println(error);
	}
}

配置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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	 <!-- target object -->
	 <bean id="userDao" class="com.aop.UserDaoImpl"/>
	 
	 <!-- 切面 :环绕通知-->
	 <bean id="logAspect" class="com.aop.LogAspect"/>
	 <!-- 前置通知 -->
	 <bean id="logBeforeAspect" class="com.aop.LogBeforeAspect"/>
	 <!-- 后置通知 -->
	  <bean id="logAfterAspect" class="com.aop.LogAfterAspect"/>
	<!-- 异常通知 -->
	<bean id="logThrowingAspect" class="com.aop.LogThrowingAspect"/>
	 
	 <!-- aop的代理:  ProxyFactoryBean -->
	 <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
	 	<!-- 需要代理哪些接口? -->
	 	<property name="proxyInterfaces" value="com.aop.UserDao"/>
	 	<!-- 目标对象? ref 表示引用类型 -->
	 	<property name="target" ref="userDao"/>
	 	<!-- 拦截器的名字: 也就是切面类的名字 ? -->
	 	<!-- <property name="interceptorNames" value="logAspect"/> -->
	 	<!-- 	<property name="interceptorNames" value="logBeforeAspect"/> -->
	 	<!-- <property name="interceptorNames" value="logAfterAspect"/> -->
	 	<property name="interceptorNames" value="logThrowingAspect"/>
	 	<!-- 代理类是不是接口,false表示JDK代理 -->
	 	<property name="proxyTargetClass" value="false"/>
	 </bean> 
	 
</beans>

 

运行测试,你会发现没有异常通知提醒,因为我们的程序是正常的,程序没有异常是不会进行通知的。

所以我们修改下addUser(),让他程序异常。就可以进行捕获异常,并且通知

package com.aop;

public class UserDaoImpl implements UserDao {

	@Override
	public void addUser(String id, String name) {
		String uid = null;
		uid.charAt(0);
		System.out.println("==============addUser方法 逻辑执行============");
	}

}

 

测试:

 

第四:引介通知

如果userDao不满足我们的需求,我们需要新增方法insert, 正常情况下是可以通过继承来额外增加方法。比较麻烦,所以可以使用引介通知,不需要去继承,可以进行解耦,减少类之间的联系

 

package com.aop;

public interface EUserDao {
	public void insertUser();
}

实现类: 需要实现 EUserDao, IntroductionInterceptor接口

 

package com.aop;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.IntroductionInterceptor;

public class EUserDaoImpl implements EUserDao, IntroductionInterceptor {

	@Override
	public Object invoke(MethodInvocation arg0) throws Throwable {
		// 判断是哪种类型接口? EUserDao
		if(implementsInterface(arg0.getMethod().getDeclaringClass())) {
			// 如果是EUserDao类型,就去运行 EUserDao中的方法
			return arg0.getMethod().invoke(this, arg0.getArguments());
		}else {
			return arg0.proceed();
		}
	}

	@Override
	public boolean implementsInterface(Class<?> arg0) {
		// 实现的接口是否为EUserDao.class
		return arg0.isAssignableFrom(EUserDao.class);
	}

	@Override
	public void insertUser() {
		// TODO Auto-generated method stub
		System.out.println("=========insertUser============新的方法执行逻辑");
	}

}

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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	 <!-- target object -->
	 <bean id="userDao" class="com.aop.UserDaoImpl"/>
	 <bean id="eUserDao" class="com.aop.EUserDaoImpl"/>
	 
	 <!-- 切面 :环绕通知-->
	 <bean id="logAspect" class="com.aop.LogAspect"/>
	 <!-- 前置通知 -->
	 <bean id="logBeforeAspect" class="com.aop.LogBeforeAspect"/>
	 <!-- 后置通知 -->
	  <bean id="logAfterAspect" class="com.aop.LogAfterAspect"/>
	<!-- 异常通知 -->
	<bean id="logThrowingAspect" class="com.aop.LogThrowingAspect"/>
	<!-- 引介通知 -->
	 <bean id="userDaoAspect" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
	 	<constructor-arg ref="eUserDao"/>
	 	<constructor-arg value="com.aop.EUserDao"/>
	 </bean>
	 
	 <!-- aop的代理:  ProxyFactoryBean -->
	 <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
	 	<!-- 需要代理哪些接口? -->
	 	<property name="proxyInterfaces" value="com.aop.UserDao"/>
	 	<!-- 目标对象? ref 表示引用类型 -->
	 	<property name="target" ref="userDao"/>
	 	<!-- 拦截器的名字: 也就是切面类的名字 ? -->
	 	<!-- <property name="interceptorNames" value="logAspect"/> -->
	 	<!-- 	<property name="interceptorNames" value="logBeforeAspect"/> -->
	 	<!-- <property name="interceptorNames" value="logAfterAspect"/> -->
	 	<!-- <property name="interceptorNames" value="logThrowingAspect"/> -->
	 	<property name="interceptorNames" value="userDaoAspect"/>
	 	<!-- 代理类是不是接口,false表示JDK代理 -->
	 	<property name="proxyTargetClass" value="false"/>
	 </bean> 
	 
</beans>

 

测试

package com.aop;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

class TestUserDao {

	@Test
	void testAddUser() {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserDao userDao = context.getBean("userDaoProxy", UserDao.class);
		//userDao.addUser("test11", "Terry");
		((EUserDao)userDao).insertUser();
	}

}

结果:能够直接调用到EuserDao中的方法

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逼哥很疯狂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值