2023-08-31 11:30:31 +08:00
|
|
|
|
# 第三章:Spring AOP
|
|
|
|
|
|
|
|
|
|
代理:
|
|
|
|
|
|
|
|
|
|
生活中的代理: 代购(代理对象):卖化妆品 代理 韩国卖化妆品的那个商店(被代理对象):卖化妆品
|
|
|
|
|
|
|
|
|
|
代理对象和被代理对象的区别?
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
代理对象可以完成被代理对象的功能,除此之外,代理对象还可以添加额外功能
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
示例:
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.gzh;
|
|
|
|
|
//韩国商店
|
|
|
|
|
public class Shop {
|
|
|
|
|
void sell(){
|
|
|
|
|
System.out.println("韩国商店卖化妆品100元");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.gzh;
|
|
|
|
|
|
|
|
|
|
public class Daigou {
|
|
|
|
|
private Shop shop;
|
|
|
|
|
|
|
|
|
|
public void setShop(Shop shop) {
|
|
|
|
|
this.shop = shop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sell(){
|
|
|
|
|
System.out.println("代购要收十元小费");
|
|
|
|
|
shop.sell();
|
|
|
|
|
System.out.println("代购卖化妆品110元");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.gzh;
|
|
|
|
|
//Test类模拟买化妆品的人
|
|
|
|
|
public class Test {
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
Daigou daigou = new Daigou();
|
|
|
|
|
daigou.setShop(new Shop());
|
|
|
|
|
daigou.sell();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
运行截图:
|
|
|
|
|
|
2023-08-31 12:43:36 +08:00
|
|
|
|
![image-20220323125142944](https://lsky.hhdxw.top/imghub/img/image-20220323125142944.png)
|
2023-08-31 11:30:31 +08:00
|
|
|
|
|
|
|
|
|
## AOP术语
|
|
|
|
|
|
|
|
|
|
AOP:面向切面编程
|
|
|
|
|
|
|
|
|
|
(1)Aspect(切面):本质就是类,例如:MyAspect,切面类完成额外功能或非核心业务功能。
|
|
|
|
|
|
|
|
|
|
(2)Joinpoint(连接点):目标方法的调用的前和后都可以称为连接点,目标方法在被代理类中
|
|
|
|
|
|
|
|
|
|
(3)pointcut(切入点):就是 切入了额外功能的 连接点
|
|
|
|
|
|
|
|
|
|
(4)Advice(通知、增强处理):就是额外功能
|
|
|
|
|
|
|
|
|
|
(5)Target Object(目标对象):被代理对象。例如:com.jdk.UserDaoImpl
|
|
|
|
|
|
|
|
|
|
(6)Proxy(代理):代理对象
|
|
|
|
|
|
|
|
|
|
(7)Weaving(织入):产生代理对象的过程,例如;createProxy
|
|
|
|
|
|
|
|
|
|
## 3.2.1 JDK动态代理
|
|
|
|
|
|
|
|
|
|
代理是谁?(或者说被代理对象是谁)?是实现了接口的类:com.jdk.UserDaoImpl
|
|
|
|
|
|
|
|
|
|
额外功能所在的类? MyAspect类
|
|
|
|
|
|
|
|
|
|
如何产生代理对象? JdkProxy类
|
|
|
|
|
|
|
|
|
|
代理对象的额外功能是如何完成的?
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.jdk;
|
|
|
|
|
|
|
|
|
|
public interface UserDao {
|
|
|
|
|
void addUser();
|
|
|
|
|
void deleteUser();
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.jdk;
|
|
|
|
|
//被代理对象就是这个实现类,该类中的方法叫做目标方法
|
|
|
|
|
public class UserDaoImpl implements UserDao{
|
|
|
|
|
@Override
|
|
|
|
|
public void addUser() {
|
|
|
|
|
System.out.println("添加用户");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void deleteUser() {
|
|
|
|
|
System.out.println("删除用户");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.jdk;
|
|
|
|
|
//额外的功能:在目标方法调用前,调用check_permission;在目标方法调用后条用log方法
|
|
|
|
|
public class MyAspect {
|
|
|
|
|
public void check_permission(){
|
|
|
|
|
System.out.println("模拟权限检查");
|
|
|
|
|
}
|
|
|
|
|
public void log(){
|
|
|
|
|
System.out.println("模拟记录日志");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.jdk;
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.InvocationHandler;
|
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
import java.lang.reflect.Proxy;
|
|
|
|
|
|
|
|
|
|
//产生代理对象的类
|
|
|
|
|
public class JdkProxy implements InvocationHandler {
|
|
|
|
|
private UserDao userDao;
|
|
|
|
|
//方法的返回值是代理对象
|
|
|
|
|
public Object createProxy(UserDao userDao){
|
|
|
|
|
this.userDao=userDao;
|
|
|
|
|
ClassLoader classLoader= JdkProxy.class.getClassLoader();
|
|
|
|
|
Class[] clazz=userDao.getClass().getInterfaces();
|
|
|
|
|
return Proxy.newProxyInstance(classLoader,clazz,this);
|
|
|
|
|
}
|
|
|
|
|
//invoke方法就是代理对象完成目标功能和额外功能的方法
|
|
|
|
|
@Override
|
|
|
|
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
|
|
|
|
MyAspect myAspect=new MyAspect();
|
|
|
|
|
myAspect.check_permission();
|
|
|
|
|
Object obj = method.invoke(userDao,args);//当程序指向到此语句时,转而调用目标方法
|
|
|
|
|
myAspect.log();
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.jdk;
|
|
|
|
|
|
|
|
|
|
public class JdkTest {
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
//被代理对象
|
|
|
|
|
UserDao userDao = new UserDaoImpl();
|
|
|
|
|
userDao.addUser();
|
|
|
|
|
System.out.println("----------------");
|
|
|
|
|
//生成代理对象
|
|
|
|
|
JdkProxy jdkProxy = new JdkProxy();
|
|
|
|
|
UserDao proxy = (UserDao) jdkProxy.createProxy(userDao);
|
|
|
|
|
proxy.addUser();//当程序指向到此语句时,转而执行invoke方法
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
运行截图:
|
|
|
|
|
|
2023-08-31 12:43:36 +08:00
|
|
|
|
![image-20220323150132535](https://lsky.hhdxw.top/imghub/img/image-20220323150132535.png)
|
2023-08-31 11:30:31 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 3.2.2CGLIB代理
|
|
|
|
|
|
|
|
|
|
代理是谁?(或者说被代理对象是谁)?User类,有两个目标方法:addUser() deleteUser()
|
|
|
|
|
|
|
|
|
|
额外功能所在的类? MyAspect类
|
|
|
|
|
|
|
|
|
|
如何产生代理对象? CglibProxy类中的方法
|
|
|
|
|
|
|
|
|
|
代理对象的额外功能是如何完成的?
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.cglib;
|
|
|
|
|
|
|
|
|
|
public class User {
|
|
|
|
|
void addUser() {
|
|
|
|
|
System.out.println("添加用户");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleteUser() {
|
|
|
|
|
System.out.println("删除用户");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.cglib;
|
|
|
|
|
|
|
|
|
|
//额外的功能:在目标方法调用前,调用check_permission;在目标方法调用后条用log方法
|
|
|
|
|
public class MyAspect {
|
|
|
|
|
public void check_permission() {
|
|
|
|
|
System.out.println("模拟权限检查");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void log() {
|
|
|
|
|
System.out.println("模拟记录日志");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.cglib;
|
|
|
|
|
|
|
|
|
|
import org.springframework.cglib.proxy.Enhancer;
|
|
|
|
|
import org.springframework.cglib.proxy.MethodInterceptor;
|
|
|
|
|
import org.springframework.cglib.proxy.MethodProxy;
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
|
|
|
|
|
public class Cglibproxy implements MethodInterceptor {
|
|
|
|
|
public Object createProxy(Object target) {
|
|
|
|
|
Enhancer enhancer = new Enhancer();
|
|
|
|
|
enhancer.setSuperclass(target.getClass());
|
|
|
|
|
enhancer.setCallback(this);
|
|
|
|
|
return enhancer.create();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
|
|
|
|
|
MyAspect myAspect = new MyAspect();
|
|
|
|
|
myAspect.check_permission();
|
|
|
|
|
Object obj = methodProxy.invokeSuper(proxy, args);//程序执行到此条语句时,转而执行目标方法
|
|
|
|
|
myAspect.log();
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
package com.cglib;
|
|
|
|
|
|
|
|
|
|
public class cglibTest {
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
//被代理对象
|
|
|
|
|
User user = new User();
|
|
|
|
|
user.addUser();
|
|
|
|
|
System.out.println("---------------");
|
|
|
|
|
//代理对象
|
|
|
|
|
Cglibproxy cglibProxy = new Cglibproxy();
|
|
|
|
|
User proxy = (User) cglibProxy.createProxy(user);
|
|
|
|
|
proxy.addUser();//程序执行到此条语句时,转为执行intercept方法
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
运行截图如下:
|
|
|
|
|
|
2023-08-31 12:43:36 +08:00
|
|
|
|
![image-20220324113512719](https://lsky.hhdxw.top/imghub/img/image-20220324113512719.png)
|
2023-08-31 11:30:31 +08:00
|
|
|
|
|
|
|
|
|
JDK代理和CGLIB代理方式的缺点?
|
|
|
|
|
|
|
|
|
|
代理对象不管调用哪一种目标方法时,都会调用额外的功能。
|
|
|
|
|
|
|
|
|
|
能不能有一种手段:可以使得程序员自己自由指定那些目标被调用时,调用额外的功能呢?Spring
|