面向切面编程(AOP)
面向切面的编程:指很多功能都有重复的代码,把这些重复的代码独立出来实现,再在运行的时候动态加入“切面类代码”。
AOP是一种设计思想,和具体的代码实现无关。
优点:
A、把共性功能和核心业务功能解耦。
B、共性代码的复用性
C、动态删除或增加切面类,不影响原来的代码
Aop的实现
前置通知,后置通知,环绕通知、异常通知
用添加日志文件为例,描述前置通知,后置通知,环绕通知三种通知,即把核心类和切面类组合的方式
以下均是XML配置方式声明切面
1、前置通知
(1)、定义接口 IStudent
public interface IStudent{
public boolean add(String id,String name);
public boolean update(String id;String name);
public boolean delete(String id);
}
注:将方法返回值定义为boolean是为了通过booleanValue()方法将值返回给切面类
(2)、实现接口的实体类StudentDao
public class StudentDao implements IStudent{
public boolean add(String id,String name){
System.out.println("正在实现 sava 方法");
System.out.println("添加学生编号:"+id+" 姓名:"+name);
return true;
}
public boolean update(String id,String name){
System.out.println("正在实现 update 方法");
System.out.println("修改学生编号:"+id+" 姓名:"+name);
return true;
}
public boolean delete(String id){
System.out.println("正在实现 delete 方法");
System.out.println("删除学生编号:"+id);
return true;
}
}
(3)、定义切面类BeforeAdvice 需要实现MethodBeforeAdvice接口
public class BeforeAdvice implements MethodBeforeAdvice{
public void befor(Method targetMethod,Object[] methodArgs,Object targetClass){
String className=targetClass.getClass().getName();//类名
String methodName=targetMethod.getName();//方法名
//获取具体的操作时间并记录
Date date=new Date();
String currentTime=DateFormat.getDateInstance().format(date); //获取当前时间并转化成字符串
String messge="【"+currentTime+“】”+className+"."+methodName+"方法被执行";
System.out.println(message);
}
}
注:befor()方法中的参数Method targetMethod表执行的是核心代码的哪个方法,Object[] methodArgs表核心代码中的所有方法,Object targetClass表要找的目标类
(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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="stuPoint" class="com.bean.StudentDao"/><!--核心业务类-->
<bean id="beforeLogin" class="com.bean.BeforeAdvice"/><!--切面类-->
<!--导入包中自带的类 是一个代理工厂类 用来组合核心类和切面类-->
<bean id="studentfactory" class="org.springframework.aop.framewoke.proxyFactoryBean">
<property name="proxyInterfaces"> <!--核心业务接口-->
<value>com.bean.Istudent</value>
</property>
<property name="interceptorNames"> <!--切面类-->
<value>beforeLogin</value>
</property>
<property name="target" ref="stuPoint"/> <!--核心类-->
</bean>
</beans>
注:配置文件名最好不变applicationContext.xml,否则需在web.xml中配置
(5)、创建StudentServlet
......
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
ApplicationContext ac=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext);
IStudent stu=(IStudent)ac.getBean("studentfactory"); //代理工厂类的id
stu.add("111","张三");
stu.update("111","李思");
stu.delete("111");
}
(6)、配置web.xml
<listener>
<listener-calss>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>StudentServlet</servlet-name>
<servlet-class>com.bean.StudentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StudentServlet</servlet-name>
<url-pattern>/aop</url-pattern>
</servlet-mapping>
(7)、将web项目发布到服务器上,在地址栏中输入aop,验证结果
2、后置通知
步骤1、2、5、6、7同上
(3)、修改切面类AfterAdvice,需要实现AfterRetruningAdvice接口
public void afterReturning(Object returnValue,Method targetMehod,Object[] methodArgs,Object targetClass){
boolean success=((Boolean)returnValue).booleanValue();
if(success){
String methodName=targetMethod.getName();
String className=targetClass.getClass().getName();
Date date=new Date();
String currentTime=DateFormat.getDateInstance().format(date);
String str="【"+currentTime+"】"+className+"."+methodName+"方法被执行";
}
}
注:Object returnValue表核心业务代码某个方法的返回值
(4)、在applicationContext.xml配置文件中,只需修改切面类即可
3、环绕通知
步骤1、2、5、6、7同上
(3)、切面类ArroundAdvice,需实现MethodInterceptor接口
public class ArroundAdvice implemets MethodInterceptor{
public Object invoke (MethodInvocation invocation){
System.out.println("开始执行"+invocation.getMethod().getName+"方法");
Object obj=invocation.proceed();
System.out.println("结束执行"+invocation.getMethod().getName+"方法");
return obj;
}
}
(4)、相同方式修改配置文件
4、异常通知
需实现org.springframework.aop.ThrowsAdvice接口,不需实现其中方法
public class ThrowTest implemets ThrowsAdvice{
public void afterThrow([method],[args],[target],subclassofThrowable){
//异常处理代码
}
}
注:subclassofThrowable表Throwable的自类,即子类异常
总结:
前置通知:实现MethodBeforeAdvice接口,方法public void before(Method targetMethod, Object[] methodArgs, Object targetClass){}
后置通知:实现AfterReturningAdvice接口,方法public void afterReturning(Object returnValue, Method targetMethod, Object[] methodArgs,Object targetClass) {}
环绕通知:实现 MethodInterceptor接口,方法public Object invoke(MethodInvocation invocation) {}
异常通知:实现ThrowsAdvice接口,自定义方法public void afterThrowing([Method],[args],[target],subclassOfThrowable)