JAVAEE之Spring学习(三)---aop切面(一)
程序员文章站
2022-05-24 09:49:41
...
先了解AOP的相关术语:
1.通知(Advice):
通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。
2.连接点(Joinpoint):
程序能够应用通知的一 个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。
3.切入点(Pointcut)
通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,spring中允许我们方便的用正则表达式来指定
4.切面(Aspect)
通知和切入点共同组成了切面:时间、地点和要发生的“故事”
5.引入(Introduction)
引入允许我们向现有的类添加新的方法和属性(spring提供了一个方法注入的功能)
6.目标(Target)
即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
7.代理(proxy)
应用通知的对象,详细内容参见设计模式里面的代理模式
8.织入(Weaving)
把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术
通过java语言实现aop切面:
package cn.hncu.v1;
import java.lang.reflect.Method;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
//AOP的一个公式:切面=切点+通知
// Aspect=Pointcut(拦截哪些函数)+advice(在哪个时间点拦截:before,after,around)
//注意,通知Advice及其抽象类用的都是aop包中的接口
public class Demo1 {
@Test
public void t1() {
// 1被代理对象--原型对象
Person p = new Person();
// 2实现代理的工具类 --bean的代理工厂
// ProxyFactory factory = new ProxyFactory();// 低版本,不建议使用
ProxyFactoryBean factory = new ProxyFactoryBean();
// 3给代理工厂设置原型
factory.setTarget(p);
// 切面=切点+通知
// 4声明切点
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
// 5为切点设置正则表达式
pointcut.setPattern(".*run.*");
// 6定义通知
Advice advice = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("前面拦拦");
// 放行
Object returnValue = invocation.proceed();
System.out.println("后面拦拦");
return returnValue;
}
};
// Advisor = cut+advice
// 7声明切面
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
// 8把切面设置到代理工厂中
factory.addAdvisor(advisor);
// 9从代理工厂中获取代理后的对象
Person p2 = (Person) factory.getObject();
// 10用代理后的对象去执行
p2.run();
}
@Test
public void t2() {
// 1被代理对象--原型对象
Person p = new Person();
// 2实现代理的工具类 --bean的代理工厂
// ProxyFactory factory = new ProxyFactory();// 低版本,不建议使用
ProxyFactoryBean factory = new ProxyFactoryBean();
// 3给代理工厂设置原型
factory.setTarget(p);
// 切面=切点+通知
// 4声明切点
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
// 5为切点设置正则表达式
pointcut.setPatterns(new String[] { ".*run.*", ".*hello.*" });
// 6定义通知(前置通知)
Advice before = new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("before...");
}
};
Advice after = new AfterReturningAdvice() {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("方法执行完毕 ");
}
};
// Advisor = cut+advice
// 7声明切面
Advisor advisor = new DefaultPointcutAdvisor(pointcut, before);
Advisor advisor2 = new DefaultPointcutAdvisor(pointcut, after);
// 8把切面设置到代理工厂中
factory.addAdvisors(advisor, advisor2);
// 9从代理工厂中获取代理后的对象
Person p2 = (Person) factory.getObject();
// 10用代理后的对象去执行
p2.run();
p2.hello();
}
}
二、通过xml配置来实现aop切面
实现类:
package cn.hncu.v1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/*
* 用xml方式来实现aop
*/
public class demo2 {
@Test
public void t1() {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"cn/hncu/v1/v1.xml");
Person p = ctx.getBean("proxiedPersonFactory", Person.class);
p.run();// 拦
p.hello();// 不拦
}
}
advice定义通知类:
package cn.hncu.v1;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("前面拦拦");
// 放行
Object returnValue = invocation.proceed();
System.out.println("后面拦拦");
return returnValue;
}
}
通过仿照java方式通过容器来进行xml配置aop切面:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/aop" 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="p" class="cn.hncu.v1.Person">
</bean>
<bean id="cut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*run.*"></property>
</bean>
<bean id="advice" class="cn.hncu.v1.AroundAdvice">
</bean>
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="cut"></property>
<property name="advice" ref="advice"></property>
</bean>
<bean id="proxiedPersonFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="p"></property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
</bean>
</beans>
推荐阅读
-
Spring之重点知识 IOC(控制反转)和AOP(面向切面编程)学习小结
-
Spring面向切面编程(AOP)三之AOP的使用及配置
-
Spring框架(Framework)之IOC(控制反转)和AOP(面向切面编程)核心特性学习
-
Spring面向切面编程(AOP)原理一之使用JDK实现动态代理
-
JAVAEE之Spring学习(三)---通过aop切面实现事务处理
-
spring框架学习之路(一)-入门基础(2)-动态代理和AOP(面向切面编程)
-
JAVAEE之Spring学习(三)---aop切面(一)
-
Spring 学习 之 动态代理实现AOP切面
-
Spring学习 之 AOP切面执行顺序的控制
-
Spring学习 之 AOP切面 声明切点表达式