一、导图
二、代理模式
代理模式的两个设计原则:
- 代理类 与 委托类 具有相似的行为(共同)
- 代理类增强委托类的行为
一、静态代理
某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
注:静态代理对于代理的角色是固定的,如 dao 层有 20 个 dao 类,如果要对方法的访问权限进行代理,此时需要创建20 个静态代理角色,引起类爆炸,无法满足生产上的需要,于是就催生了动态代理的思想。
二、动态代理
Java反射机制动态产生。它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为反射机制可以生成任意类型的动态代理类。代理的行为可以代理多个方法,即满足生产需要的同时又达到代码通用的目的。
1.JDK动态代理
a、每一个代理类都需要实现InvocationHandler接口
b、Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下操作方法:
/*
返回一个指定接口的代理类的实例方法调用分派到指定的调用处理程序。 (返回代理对象)
loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果 我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:一个InvocationHandler接口,表示代理实例的调用处理程序实现的接口。每个代理实例都具有一个 关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的invoke方法(传入InvocationHandler接口的子类)
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
JDK动态代理类:
1.把目标对象传给代理类,调用getProxy()方法(里面调用了Proxy.newProxyInstance()生成了一个代理)得到代理对象
//目标对象
Owner owner = new Owner();
//得到代理类
JdkHandler jdkHandler1 = new JdkHandler(owner);
//得到代理对象
RentHouse rentHouse = (RentHouse) jdkHandler1.getProxy();
//通过代理对象调用目标对象的方法
rentHouse.toRentHouse();
2.因为JdkHandler implements InvocationHandler;只要通过代理对象调用的方法,最终会由它的底层代码转向调用invoke()方法。即上面rentHouse.toRentHouse();最终执行invoke。
3.代码如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK动态代理类
* 每一个代理类都需要实现InvocationHandler接口
*/
public class JdkHandler implements InvocationHandler {
//目标对象
private Object target; //目标对象类型不固定 创建时动态生成
//通过带参构造器传递目标对象
public JdkHandler(Object target) {
this.target = target;
}
/**
* 1. 调用目标对象的方法 (返回Object)
* 2. 增强目标对象的行为
*
* @param proxy 调用该方法的代理实例
* @param method 目标对象的方法
* @param args 目标对象的方法所需要的的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke方法的proxy参数:"+proxy.getClass().getName());
//用户的增强行为
System.out.println("------方法执行前------");
//调用目标对象的方法(返回Object类型)
Object obj = method.invoke(target, args);
//用户的增强行为
System.out.println("------方法执行后------");
// return null;
return obj;
}
/**
* 获取代理对象
* public static Object newProxyInstance(ClassLoader loader,
* Class[] interfaces,
* InvocationHandler h)
* loader:类加载器
* interfaces:接口数组
* target.getClass().getInterfaces():目标对象的接口数组
* h:InvocationHandler接口(传入InvocationHandler接口的实现类)
*
* @return
*/
public Object getProxy(){
Object obj = Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
System.out.println("getProxy返回的代理对象:"+obj.getClass().getName());
return obj;
}
}
问:Java动态代理类中的invoke是怎么调用的?
注: JDK 的动态代理依靠接口实现,如果有些类并没有接口实现,则不能使用 JDK 代理。
2. CGLIB动态代理
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
而jdk代理不需要添加依赖:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
3.JDK代理与CGLIB代理的区别
- JDK动态代理实现接口,Cglib动态代理继承思想
- JDK动态代理(目标对象存在接口时)执行效率高于Ciglib
- 如果目标对象有接口实现,选择JDK代理,如果没有接口实现选择Cglib代理
三、Spring AOP
什么是AOP?
AOP能做什么?
AOP的特点
AOP的底层实现:动态代理(JDK + CGLIB)
AOP基本概念
1 连接点 Joint point:
类里面那些可以被增强的方法,这些方法称之为连接点
2 切入点 Pointcut:
实际被增强的方法,称之为切入点
3 通知 Advice:
实际增强的逻辑部分称为通知 (增加的功能)
织入 Advice 的目标对象
5 切面Aspect: 表现为功能相关的一些advice方法放在一起声明成的一个Java类
Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程
两种实现:
1.注解实现
2.xml实现