Spring——AOP
一、AOP:面向切面编程;
底层实现:
1)代理类有接口:使用JDK动态代理;
2)代理类有接口:可以强制使用CGlib动态代理;
3)代理类没有接口:使用CGlib动态代理;
二、概念:
1)连接点(Join point):
能够被拦截的地方:Spring AOP是基于动态代理的,所以是方法拦截的。每个成员方法都可以称之为连接点;
2)切点(Poincut):
具体定位的连接点:上面也说了,每个方法都可以称之为连接点,具体定位到某一个方法就成为切点。
3)增强/通知(Advice):
表示添加到切点的一段逻辑代码,并定位连接点的方位信息。
Spring AOP提供了5种Advice类型:前置、后置、返回、异常、环绕;
4)织入(Weaving):
将增强/通知添加到目标类的具体连接点上的过程。
5)引入/引介(Introduction):
引入/引介允许我们向现有的类添加新方法或属性。是一种特殊的增强!
6)切面(Aspect):
切面由切点和增强/通知组成,它既包括了横切逻辑的定义、也包括了连接点的定义。
三、通知类型:实现相应的接口;
|
通知类型 |
实现接口 |
接口方法 |
xml标签 |
注释 |
|
前置通知 |
MethodBeforeAdvice |
before() |
<aop:before> |
@Before(value="") |
|
后置通知 |
AfterReturningAdvice |
afterReturning() |
<aop:after-returning> |
@AfterReturning("") |
|
异常通知 |
ThrowsAdvice |
afterThrowing() //需要自己实现 |
<aop:after-throwing> |
@AfterThrowing("") |
|
最终通知 |
/ |
after() |
<aop:after> |
@After("") |
|
环绕通知 |
MethodInterceptor |
invoke() |
<aop:around> |
@Around(value="") |
四、XML配置使用示例:
1)导入依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency>
2)配置beans标签约束:
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
3)配置通知:
1、<aop:advisor ></aop:advisor>:一般用于事务管理;
//切面所在类需要实现接口;
public class LogBefore implements MethodBeforeAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("前置通知"); } } public class LogAfter implements AfterReturningAdvice { @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("后置通知"); } } public class LogException implements ThrowsAdvice { public void afterThrowing(Method method, Object[] args, Object target, Exception ex){ System.out.println("异常通知"); System.out.println(method.getName()); System.out.println(ex.getMessage()); } } public class LogAround implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { try { System.out.println("前置通知"); //切点方法执行; Object proceed = invocation.proceed(); System.out.println("后置通知"); } catch (Exception e) { e.printStackTrace(); System.out.println("异常通知"); } finally { System.out.println("最终通知"); } return null; } }
public class UserManager { public void addStudent(User user) { //System.out.println(3/0); System.out.println("增加用户"); } }
<?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="userManager" class="com.qf.aop.UserManager"></bean> <bean id="logAfter" class="com.qf.aop.LogAfter"></bean> <bean id="logBefore" class="com.qf.aop.LogBefore"></bean> <bean id="logException" class="com.qf.aop.LogException"></bean> <bean id="logAround" class="com.qf.aop.LogAround"></bean> <aop:config> <!--配置切入点--> <aop:pointcut id="point" expression="execution(* com.qf.aop.UserManager.*(..))"></aop:pointcut> <!--配置切入点和切面连接,相当于连接线--> <!--<aop:advisor advice-ref="logAfter" pointcut-ref="point"></aop:advisor>--> <!--<aop:advisor advice-ref="logBefore" pointcut-ref="point"></aop:advisor>--> <!--<aop:advisor advice-ref="logException" pointcut-ref="point"></aop:advisor>--> <aop:advisor advice-ref="logAround" pointcut-ref="point"></aop:advisor> </aop:config> </beans>
public class T { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml"); UserManager userManager = context.getBean(UserManager.class); userManager.addStudent(new User()); } }
2、<aop:aspect ></aop:aspect>:一般用于日志,缓存;
public class Log { public void before() { System.out.println("前置通知"); } public void afterReturning() { System.out.println("后置通知(方法不出现异常)"); } public void afterException() { System.out.println("异常通知"); } public void after() { System.out.println("最终通知(方法不出现异常)"); } }
public class UserManager { public void addStudent(User user) { //System.out.println(3/0); System.out.println("增加用户"); } }
<?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="userManager" class="com.qf.aop.UserManager"></bean> <bean id="log" class="com.qf.aop.Log"></bean> <aop:config> <aop:pointcut id="point" expression="execution(* com.qf.aop.UserManager.*(..))"></aop:pointcut> <aop:aspect ref="log"> <aop:before method="before" pointcut-ref="point"></aop:before> <aop:after-returning method="afterReturning" pointcut-ref="point"></aop:after-returning> <aop:after method="after" pointcut-ref="point"></aop:after> <aop:after-throwing method="afterException" pointcut-ref="point"></aop:after-throwing> <aop:around method="afterException" pointcut-ref="point"></aop:around> </aop:aspect> </aop:config> </beans>
public class T { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml"); UserManager userManager = context.getBean(UserManager.class); userManager.addStudent(new User()); } }
五、execution表达式:
1)关键字:execution(表达式)
2)表达式:访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
3)标准写法:public void com.qf.dao.UserManager.addUser(User user)
4)访问修饰符可以省略:
void com.qf.dao.UserManager.addUser(User user)
5)返回值可以使用通配符,表示任意返回值:
* com.qf.dao.UserManager.addUser(User user)
6)包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* *.*.*.UserManager.addUser(User user)
7)包名可以使用..表示当前包及其子包:
* *..UserManager.addUser(User user)
8)类名和方法名都可以使用*来实现通配:
* *..*.*(User user)
9)参数列表:
1.可以直接写数据类型:
i.基本类型直接写名称:int
ii.引用类型写包名.类名的方式:java.lang.String
2.可以使用通配符表示任意类型,但是必须有参数;
3.可以使用..表示有无参数均可,有参数可以是任意类型;
10)全通配写法:
* *..*.*(..)
11)实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法:* com.qf.dao.UserManager.*(..)
<aop:pointcut id="ponitcut" expression="execution(* com.qf.dao.UserManager.*(..))"></aop:pointcut>

浙公网安备 33010602011771号