SpringAOP面向切面编程
AOP的作用:
在不修改原有代码的基础上完成功能的扩展
AOP的方式:
AOP的Schema-based方式实现
①导入jar包 AOP的jar和IOC的jar
链接:https://pan.baidu.com/s/17cxb5fPX83CVDAJ67IwPLg
提取码:jxv7
②配置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置学生的bean 注意生成的代理的对象要和学生类实现同一个接口-->
<bean id="stu" class="pojo.StudentImpl"></bean>
<!--配置前置通知bean,部件 实现MethodBeforeAdvice接口-->
<bean id="a" class="advice.Before"></bean>
<!--配置后置通知bean,部件 实现AfterReturningAdvice接口-->
<bean id="b" class="advice.After"></bean>
<!--配置环绕通知bean:部件,实现MethodInterceptor接口-->
<bean id="c" class="advice.MyRound"></bean>
<!--配置异常通知bean:部件,实现ThrowsAdvice接口-->
<bean id="d" class="advice.MyThrow"></bean>
<aop:config>
<!--声明切点,如果有返回值,在方法中只声明返回值的类型 例如show(String,int)-->
<aop:pointcut id="my" expression="execution(* pojo.StudentImpl.show())"></aop:pointcut>
<!--将切点和通知组装起来-->
<aop:advisor advice-ref="a" pointcut-ref="my"></aop:advisor>
<aop:advisor advice-ref="b" pointcut-ref="my"></aop:advisor>
<aop:advisor advice-ref="c" pointcut-ref="my"></aop:advisor>
<aop:advisor advice-ref="d" pointcut-ref="my"></aop:advisor>
</aop:config>
</beans>
③使用扩展对象完成功能开发。
Student接口,实际对象和代理对象都要实现这个接口
public interface Student {
void show();
}
后置通知类
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
/**
* 后置通知类:
* 声明:实现AfterReturningAdvice接口
* 作用:在切点执行之后执行.
* 使用:需要在applicationcontext.xml中配置为bean标签,同时引入到切面声明中
* 方法:afterReturning
* 参数:
* Object o:切点执行的返回值
* Method method:切点方法的方法对象
* Object[] objects:实参的数组
* Object o1:切点所隶属的对象,真实对象。
*/
public class After implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("我是后置通知");
}
}
前置通知类
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
* 前置通知类:
* 声明:实现MethodBeforeAdvice接口
* 作用:在切点执行之前执行.
* 使用:需要在applicationcontext.xml中配置为bean标签,同时引入到切面声明中
* 方法:before
* 参数:
* Method method:切点方法的方法对象
* Object[] objects:实参的数组
* Object o:切点所隶属的对象,真实对象。
*/
public class Before implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("我是前置通知");
// method.invoke(o,objects);
}
}
环绕通知类
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* 环绕通知类:
* 声明:实现MethodInterceptor接口
* 作用:环绕执行,拦截切点。需要放行.类似于拦截器
* 使用:需要在applicationcontext.xml中配置为bean标签,同时引入到切面声明中
* 方法:invoke
* 参数:
* MethodInvocation methodInvocation
*/
public class MyRound implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("环绕前");
Object proceed = methodInvocation.proceed();//放行,类似于拦截器
System.out.println("环绕后");
return proceed;
}
}
异常通知类
import org.springframework.aop.ThrowsAdvice;
/**
* 异常通知类:
* 声明:实现ThrowsAdvice接口
* 作用:处理代理对象执行的异常信息,如果出现异常会执行这个通知类
* 使用:需要在applicationcontext.xml中配置为bean标签,同时引入到切面声明中
* 方法:afterThrowing
* 参数:
* Exception ex:接收异常信息。
*/
public class MyThrow implements ThrowsAdvice {
//方法必须时这个名
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("我是异常通知");
}
}
AOP的Aspecjt方式实现
①导入jar包 AOP的jar和IOC的jar
链接:https://pan.baidu.com/s/17cxb5fPX83CVDAJ67IwPLg
提取码:jxv7
②配置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="stu" class="pojo.Student"></bean>
<!--声明通知类-->
<bean id="advice" class="advice.MyAdvice"></bean>
<!--作用:可以声明多个,一个表示一组扩展,只对该组内切点有效-->
<aop:config>
<!--声明切点-->
<!--
配置切点:
切点的表达式支持通配符(schema和ascpectj都支持)*
pojo.Student.stuDemo(..)
表示:参数任意类型任意个数的stuDemo方法
pojo.Student.*(..)
表示:student对象中的所有方法
pojo.*.*(..)
表示:pojo包下的所有类的所有方法
一般会用在给业务层的方法进行统一增加扩展功能:
com.bjsxt.service.impl.*.*(..)
-->
<aop:pointcut id="my" expression="execution(* pojo.Student.show())"></aop:pointcut>
<!--ref属性 和通知类关联-->
<aop:aspect ref="advice">
<!--前置通知-->
<aop:before method="before" pointcut-ref="my"></aop:before>
<aop:after method="after" pointcut-ref="my"></aop:after>
<aop:around method="around" pointcut-ref="my"></aop:around>
<!--
配置异常通知方法:
需要在异常标签中使用throwing属性,属性值为异常通知方法的形参名,
来表明需要将异常信息传递给异常通知方法使用
-->
<aop:after-throwing method="Mythrow" pointcut-ref="my" throwing="e"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
接口的实现类
public class Student implements StudentInf {
@Override
public void show() {
System.out.println("我是学生");
}
}
通知类:
package advice;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
public void before(){
System.out.println("我是前置通知");
}
public void after(){
System.out.println("我是后置通知");
}
public void around(ProceedingJoinPoint pp) throws Throwable {
System.out.println("环绕前");
pp.proceed(); //放行
System.out.println("环绕后");
}
public void Mythrow(Exception e){
System.out.println("我是异常通知");
}
}
测试类
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.StudentInf;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
StudentInf stu = (StudentInf) ac.getBean("stu");
stu.show();
}
}
AOP的注解方式实现
注意:SpringAOP只有AspectJ方式可以使用注解方式完成相同配 置,SchemaBased不支持注解方式
SpringAOP的注解实现:
@Compent:
作用:相当于配置了bean标签,默认类名首字母小写为 bean的ID
使用:在类名上使用
@AspectJ:
作用:声明该类对象为通知类对象。
使用:声明在类名上,结合@Compent使用
@Pointcut:
作用:声明切点
使用:在切点方法上。
@Before:
作用:声明前置通知方法
使用:在前置通知方法上
@After:
作用:声明后置通知方法
使用:在后置通知方法上
@Around:
作用:声明环绕通知方法
使用:在环绕通知方法上
@Throwing:
作用:声明异常通知方法
使用:在异常通知方法上
配置配置文件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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--配置注解扫描-->
<context:component-scan base-package="advice,pojo"></context:component-scan>
<!--配置aop注解生效-->
<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
</beans>
学生的实现类
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
public class Student implements StudengInf {
@Override
//切点上配置方法的路径
@Pointcut("execution(* pojo.Student.show())")
public void show() {
System.out.println("我是学生");
}
}
通知类
package advice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class Myadvice {
@Before("pojo.Student.show()")
public void before(){
System.out.println("我是前置通知");
}
@After("pojo.Student.show()")
public void after(){
System.out.println("我是后置通知");
}
@Around("pojo.Student.show()")
public void round(ProceedingJoinPoint pp) throws Throwable {
System.out.println("环绕前");
pp.proceed();
System.out.println("环绕后");
}
/*throwing = "e"写的时形参的名字*/
@AfterThrowing(value = "pojo.Student.show()",throwing = "e")
public void myThrow(Exception e){
System.out.println("我是异常通知");
}
}
测试类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.StudengInf;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
/*id默认类名小写*/
StudengInf student = (StudengInf) ac.getBean("student");
student.show();
}
}