从b站学习springcloud,现在进行总结,该总结除去了视频中出现的小错误,对有些易错的地方进行了提醒
b站链接:https://www.bilibili.com/video/BV1Gt411N7HF?p=2
资料链接:
https://pan.baidu.com/s/1o0Aju3IydKA15Vo1pP4z5w
提取码: 21ru
上一节链接:
下一节链接:
下面的内容总结:
AOP:面向切面编程,不同业务 有相同的代码,这个代码重复写 多麻烦!
抽象出来,在一个位置,写1次
不同业务需要这些代码,就在某位置找到代码
AOP 是对面向对象编程的补充,在运行时,动态 将代码切入到类的指定方法、指定位置上 的编程思想就是面向切面编程。
不同方法的 同 1 个位置 抽象成 1 个切面对象,对该切面对象进行编程就是 AOP。
AOP 的优点:
- 降低模块间 耦合度
- 系统 更容易扩展
- 好的代码 复用
- 非业务代码更集中,不分散,便于统一管理
- 业务代码 更简洁、存粹,无其他代码的影响
类似 spring学习1 —— IoC,新建工程 springAOP
写一个计算机的功能,先传统方法,后 AOP 方法
1 在 pom 文件中加入代码:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.southwind</groupId>
<artifactId>springAOP</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
</dependencies>
</project>
2 在java 中创包 com.southwind.utils,其内创建接口 Cal,加入代码:
package com.southwind.utils;
public interface Cal {
public int add(int num1, int num2);
public int sub(int num1, int num2);
public int mul(int num1, int num2);
public int div(int num1, int num2);
}
传统方法
3 在 utils 中,创包Impl,其内 创建实现类 CalImpl
,传统代码:
package com.southwind.utils.Impl;
import com.southwind.utils.Cal;
public class CalImpl implements Cal {
public int add(int num1, int num2) {
System.out.println("add 方法的参数:" + num1 + "," + num2);
int result = num1 + num2;
System.out.println("add 方法的结果 = " + result);
return result;
}
public int sub(int num1, int num2) {
System.out.println("sub 方法的参数:" + num1 + "," + num2);
int result = num1 - num2;
System.out.println("sub 方法的结果 = " + result);
return result;
}
public int mul(int num1, int num2) {
System.out.println("mul 方法的参数:" + num1 + "," + num2);
int result = num1 * num2;
System.out.println("mul 方法的结果 = " + result);
return result;
}
public int div(int num1, int num2) {
System.out.println("div 方法的参数:" + num1 + "," + num2);
int result = num1 / num2;
System.out.println("div 方法的结果 = " + result);
return result;
}
}
4 在 southwind 中,创包 test,其内创建 类 Test,加入代码:
package com.southwind.test;
import com.southwind.utils.Cal;
import com.southwind.utils.Impl.CalImpl;
public class Test {
public static void main(String[] args) {
Cal cal = new CalImpl();
cal.add(1,1);
cal.sub(2,1);
cal.mul(3,4);
cal.div(5,1);
}
}
启动 test/ Test:
AOP - MyInvocationHandler 方法
传统的代码:修改起来很麻烦,加减乘除,均是 输出参数 + 输出结果
用 AOP 优化:
5 在 utils 中,新建 类 MyInvocationHandler,加入代码:
package com.southwind.utils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class MyInvocationHandler implements InvocationHandler {
// 接收委托对象
private Object object = null;
// 返回代理对象
public Object bind(Object object){
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "方法的参数:" + Arrays.toString(args));
Object result = method.invoke(this.object,args);
System.out.println(method.getName() + "的结果 = " + result);
return result;
}
}
6 utils/ Cal 的 Cal 再复制 1 份,命名为 Cal1,内容不变
Impl/ CarImpl 的 CarImpl 再复制 1 份,命名为 CalImpl1
,代码:
package com.southwind.utils.Impl;
import com.southwind.utils.Cal;
public class CalImpl1 implements Cal {
public int add(int num1, int num2) {
int result = num1 + num2;
return result;
}
public int sub(int num1, int num2) {
int result = num1 - num2;
return result;
}
public int mul(int num1, int num2) {
int result = num1 * num2;
return result;
}
public int div(int num1, int num2) {
int result = num1 / num2;
return result;
}
}
7 在 test 中,新建 类 Test1,加入代码:
package com.southwind.test;
import com.southwind.utils.Cal;
import com.southwind.utils.Impl.CalImpl1;
import com.southwind.utils.MyInvocationHandler;
public class Test1 {
public static void main(String[] args) {
Cal cal = new CalImpl1();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
Cal cal1 = (Cal) myInvocationHandler.bind(cal);
cal1.add(1,1);
cal1.sub(2,1);
cal1.mul(3,4);
cal1.div(5,1);
}
}
启动 test/ Test1:
Spring框架 实现 AOP
上面 MyInvocationHandler 用 动态代理实现 AOP,复杂、不好理解
Spring 框架封装了 AOP,不用创建 InvocationHandler,只要创建1 个切面对象
所有 非业务代码 在切面对象中完成就行,Spring 框架底层 会自动根据切面类、目标类 生成 1 个代理对象
1 在 pom 文件中,加入代码:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
2 在 utils/ Impl/ CalImpl1 中加入 @Component
3 在 southwind 中,创包 aop,其内新建 类 LoggerAspect,加入代码:
package com.southwind.aop;
import jdk.nashorn.internal.scripts.JO;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
public class LoggerAspect {
@Before(value = "execution(public int com.southwind.utils.Impl.CalImpl1.*(..))")
public void before(JoinPoint joinPoint){
// 获取 方法名
String name = joinPoint.getSignature().getName();
// 获取参数
String args = Arrays.toString(joinPoint.getArgs());
System.out.println(name + "方法的参数:" + args);
}
@After(value = "execution(public int com.southwind.utils.Impl.CalImpl1.*(..))")
public void after(JoinPoint joinPoint){
// 获取 方法名
String name = joinPoint.getSignature().getName();
System.out.println(name + "执行完毕!");
}
@AfterReturning(value = "execution(public int com.southwind.utils.Impl.CalImpl1.*(..))", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result){
//获取方法名
String name = joinPoint.getSignature().getName();
System.out.println(name + "的结果 = " + result);
}
@AfterThrowing(value = "execution(public int com.southwind.utils.Impl.CalImpl1.*(..))", throwing = "exception")
public void afterThrowing(JoinPoint joinPoint, Exception exception){
//获取方法名
String name = joinPoint.getSignature().getName();
System.out.println(name + "方法抛出异常" + exception);
}
}
4 在 resources 中新建 spring-aop.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:context="http://www.springframework.org/schema/context"
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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 自动扫描 -->
<context:component-scan base-package="com.southwind"></context:component-scan>
<!-- Aspect注解生效,为目标类 自动生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
context:component-scan:扫描 com.southwind 中 所有类,如果该类有 @Component,该类会被扫描到 IoC 容器中
aop:aspectj-autoproxy:Spring 框架结合切面类、目标类 自动生成动态代理对象
- 切面:横切关注点 被模块化的抽象对象
- 通知:切面对象 完成的工作
- 目标:被通知的对象 = 被横切的对象
- 代理:切面、通知、目标混合之后的对象
- 连接点:通知要插入业务代码的具体位置
- 切点:AOP 通过切点定位到连接点
5 在 test 中,新建 类 Test2,加入代码:
package com.southwind.test;
import com.southwind.utils.Cal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test2 {
public static void main(String[] args) {
// 配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml");
// 获取代理对象
Cal proxy = (Cal) applicationContext.getBean("calImpl1");
proxy.add(1,1);
proxy.sub(2,1);
proxy.mul(3,4);
proxy.div(5,1);
}
}
其中 getBean("calImpl1");
的 calImpl1
是默认的,它是 Impl 中的方法的名字,首字母若大写,就变成小写
也可以自己设置名字:
在 Test2 中再改就行了
启动 test/ Test2: