Spring 之 AOP
什么是 AOP?
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译形式和运行期动静代理实现程序性能的对立保护的一种技术。
目标:
利用 AOP 能够对业务逻辑的各个局部进行隔离,从而使得业务逻辑各局部之间的耦合度升高,进步程序的可重用性,同时进步了开发的效率。
作用及其劣势
作用:在程序运行期间,在不批改源码的状况下对办法进行性能加强
劣势:缩小反复代码,进步开发效率,并且便于保护
AOP 的底层实现
AOP 的底层是通过 Spring 提供的的动静代理技术实现的。在运行期间,Spring 通过动静代理技术动静的生成代理对象,代理对象办法执行时进行加强性能的染指,在去调用指标对象的办法,从而实现性能的加强。
AOP 的动静代理技术
JDK 代理 : 基于接口的动静代理技术
cglib 代理:基于父类的动静代理技术
JDK 的动静代理
①指标类接口
public interface TargetInterface {public void method();
}
②指标类
public class Target implements TargetInterface {
@Override
public void method() {System.out.println("Target running....");
}
}
③动静代理代码
Target target = new Target(); // 创立指标对象
// 创立代理对象
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass()
.getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {System.out.println("前置加强代码...");
Object invoke = method.invoke(target, args);
System.out.println("后置加强代码...");
return invoke;
}
}
);
④ 调用代理对象的办法测试
// 测试, 当调用接口的任何办法时,代理对象的代码都无需批改
proxy.method();
cglib 的动静代理
①指标类
public class Target {public void method() {System.out.println("Target running....");
}
}
②动静代理代码
Target target = new Target(); // 创立指标对象
Enhancer enhancer = new Enhancer(); // 创立增强器
enhancer.setSuperclass(Target.class); // 设置父类
enhancer.setCallback(new MethodInterceptor() { // 设置回调
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {System.out.println("前置代码加强....");
Object invoke = method.invoke(target, objects);
System.out.println("后置代码加强....");
return invoke;
}
});
Target proxy = (Target) enhancer.create(); // 创立代理对象
③调用代理对象的办法测试
// 测试, 当调用接口的任何办法时,代理对象的代码都无需批改
proxy.method();
相干常识要点
aop:面向切面编程
aop 底层实现:基于 JDK 的动静代理 和 基于 Cglib 的动静代理
aop 的重点概念:
Pointcut(切入点):被加强的办法
Advice(告诉 / 加强):封装加强业务逻辑的办法
Aspect(切面):切点 + 告诉
Weaving(织入):将切点与告诉联合的过程
开发明确事项:
谁是切点(切点表达式配置)谁是告诉(切面类中的加强办法)将切点和告诉进行织入配置
基于 XML 配置文件的 AOP 开发
①导入 AOP 相干坐标
<!-- 导入 spring 的 context 坐标,context 依赖 aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--spring 测试的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- aspectj 的织入 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
②创立指标接口和指标类(外部有切点)
public interface TestService {public void save();
}
public class TestServiceImpl implements TestService {public void save() {System.out.println("save 办法 runnning......");
}
}
③创立切面类(外部有加强办法)
public class Advice {
// 前置加强的告诉
public void before(){System.out.println("前置加强......");
}
}
④将指标类和切面类的对象创立权交给 spring
<!-- 配置指标类 -->
<bean id="testService" class="com.duanping.service.impl.TestServiceImpl"></bean>
<!-- 配置切面类 -->
<bean id="advice" class="com.duanping.advices.Advice"></bean>
⑤在 applicationContext.xml 中配置织入关系
导入 aop 命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="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
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
">
配置切点表达式和前置加强的织入关系
<!-- 配置织入:通知 spring 框架 哪些办法(切点)须要进行哪些加强(前置、后置....)-->
<aop:config>
<!-- 申明切面 引入 advice 的 bean 作为切面对象 -->
<aop:aspect ref="advice">
<!-- 切面:告诉 + 切点 配置对切点的办法进行前置加强 -->
<aop:before method="before" pointcut="execution(public void com.duanping.service.impl.TestServiceImpl.save())"></aop:before>
</aop:aspect>
</aop:config>
⑥测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private TestService testService;
@Test
public void test1(){testService.save();
}
}
⑦测试后果
XML 配置 AOP 详解
1) 切点表达式的写法
表达式语法:
execution([修饰符] 返回值类型 包名. 类名. 办法名 (参数))
拜访修饰符能够省略
返回值类型、包名、类名、办法名能够应用星号 * 代表任意
包名与类名之间一个点 . 代表以后包下的类,两个点 … 示意以后包及其子包下的类
参数列表能够应用两个点 … 示意任意个数,任意类型的参数列表
例如:
execution(public void com.itheima.aop.Target.method())
execution(void com.itheima.aop.Target.*(..))
execution(* com.itheima.aop.*.*(..))
execution(* com.itheima.aop..*.*(..))
execution(* *..*.*(..))
2) 告诉的类型
告诉的配置语法:
<aop: 告诉类型 method=“切面类中办法名”pointcut=“切点表达式 "></aop: 告诉类型 >
3) 切点表达式的抽取
当多个加强的切点表达式雷同时,能够将切点表达式进行抽取,在加强中应用 pointcut-ref 属性代替 pointcut 属性来援用抽取后的切点表达式。
<!-- 对切点的抽取 -->
<aop:pointcut id="point" expression="execution(* com.duanping.service.impl.*.*(..))"/>
<aop:before method="before" pointcut-ref="point"></aop:before>
基于注解的 AOP 开发
在配置文件中开启组件扫描和 AOP 的主动代理
<!-- 组件扫描 -->
<context:component-scan base-package="com.itheima.aop"/>
<!--aop 的主动代理 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
注解配置 AOP 详解
1) 注解告诉的类型
告诉的配置语法:@告诉注解 (“切点表达式 ”)
2) 切点表达式的抽取
同 xml 配置
aop 一样,咱们能够将切点表达式抽取。抽取形式是在切面内定义方法,在该办法上应用 @Pointcut 注解定义切点表达式,而后在在加强注解中进行援用
@Pointcut("execution(* com.duanping..*.*(..))")
public void pointcut(){}
// 前置加强的告诉
@Before("pointcut()")
public void before(){System.out.println("前置加强......");
}
常识要点
注解 aop 开发步骤
①应用 @Aspect 标注切面类
②应用 @告诉注解标注告诉办法
③在配置文件中配置 aop 主动代理 aop:aspectj-autoproxy/\
最初
大家看完有什么不懂的能够在下方留言探讨,也能够关注我私信问我,我看到后都会答复的。也能够关注我的公众号:前程有光,金三银四跳槽面试季,整顿了 1000 多道将近 500 多页 pdf 文档的 Java 面试题材料,文章都会在外面更新,整顿的材料也会放在外面。谢谢你的观看,感觉对你有帮忙的话能够专一我点个赞反对一下!