需要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中的方法