资料:
首先,简单介绍一下AOP:即面向切面编程,可以说是OOP(面向对象编程)的补充和完善。
它利用一种称为“横切”的技术,刨解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,命名为“切面”。
所谓“切面”:简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
下面用一个简单的登录来解释4种通知:
1、创建一个用户登录的 抽象类(接口)
public interface IPerson {
/**
*
* @Title: login
* @Description: 登录的方法
* @param userName
* @return void
*/
public void login(String userName);
}
2、创建一个用户登录的 真实的类(实现类):继承IPerson的接口
public class XiaoMing implements IPerson {
@Override
public void login(String userName) {
//判断:如果输入的值不为“张三”,则进入异常处理
if ("张三".equals(userName)) {
System.out.println(userName + " 正在登录系统");
} else {
throw new RuntimeException("用户名不正确");
}
}
}
3、创建一个用户登录的 前置通知的类: 实现MethodBeforeAdvice接口
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objs, Object object) throws Throwable {
String userName = (String) objs[0]; // 获取登录名
System.out.println("用户 " + userName + " 登录前处理");
}
}
创建一个用户登录的 后置通知的类: 实现AfterReturningAdvice接口
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
String userName = (String) args[0]; // 获取登录名
System.out.println(userName + " 登录成功");
}
}
创建一个用户登录的 环绕通知的类: 实现MethodInterceptor接口
public class SurroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] objs = invocation.getArguments();
String userName = (String) objs[0];
// 在目标方法执行前调用
System.out.println("正在对" + userName + "进行登录验证");
// 通过反射调用执行方法
Object obj = invocation.proceed();
// 在目标方法执行之后调用
System.out.println(userName + "登录成功");
return obj;
}
}
创建一个用户登录的 异常通知的类: 实现ThrowsAdvice接口
public class ExceptionAdvice implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] objs, Object target, Exception ex) {
System.out.println("登录名错误");
}
}
4、配置applicationContext.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"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<!-- 1、配置目标 -->
<bean id="xm" class="com.zking.springProxy.XiaoMing">
</bean>
<!-- 前置通知 -->
<bean id="beforeAdvice" class="com.zking.springProxy.BeforeAdvice"></bean>
<!-- 后置通知 -->
<bean id="afterAdvice" class="com.zking.springProxy.AfterAdvice"></bean>
<!-- 环绕通知 -->
<bean id="surroundAdvice"
class="com.zking.springProxy.SurroundAdvice"></bean>
<!-- 异常通知 -->
<bean id="exceptionAdvice"
class="com.zking.springProxy.ExceptionAdvice"></bean>
<!-- 配置通知的过滤 -->
<bean id="myInform"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- 引用前置通知 -->
<property name="advice" ref="beforeAdvice"></property>
<!-- 在方法调用的时候,会调用前置通知 -->
<!-- 以.*开头,.*结尾,中间写的是 方法名包含的内容 -->
<property name="pattern" value=".*eat.*"></property>
</bean>
<!-- 配置混合代理对象 -->
<bean id="myProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 2、引用目标 :target原对象,目标 -->
<property name="target" ref="xm"></property>
<!-- 3、目标实现的所有的接口 -->
<property name="proxyInterfaces">
<list>
<value>com.zking.springProxy.IPerson</value>
</list>
</property>
<!-- 引用通知 -->
<property name="interceptorNames">
<list>
<!-- 引用前置通知 -->
<!-- <idref bean="beforeAdvice" /> -->
<idref bean="myInform" />
<!-- 引用后置通知 -->
<idref bean="afterAdvice" />
<!-- 引用环绕通知 -->
<idref bean="surroundAdvice" />
<!-- 引用异常通知 -->
<idref bean="exceptionAdvice" />
</list>
</property>
</bean>
</beans>
5、创建一个测试类:
public class PersonTest {
@Test
public void test() {
//得到配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//创建接口
IPerson ip = (IPerson) applicationContext.getBean("myProxy");
//调用登录的方法
// ip.login("张三");
ip.login("李四");
}
}