Spring——AOP学习(静态代理和动态代理模式)
一、代理模式
我们知道学习Spring最重要的两个知识点就是IOC和AOP,AOP的主要思想就是动态代理模式。在了解AOP之前我们必须学习动态代理模式。
代理模式又分为静态代理和动态代理。
二、静态代理
在学习多线程的时候我们已经学了了静态代理,我们这里回顾一下。什么是静态代理?
拿出之前学习静态代理的例子:
加入你要结婚,是不是需要找个婚庆公司来帮你结婚,但是实际上结婚的还是你自己,婚庆公司也就是哪个代理对象,它可以帮你做婚前的准备等等工作,你只需要专注于结婚这件事就行了。这就是静态代理模式。代理角色需要和真实的角色实现一个共同的结婚接口。我们来回忆一下代码是怎么简单实现静态代理的:
/**
* 静态代理模式:
* 1.真实角色
* 2.代理角色
* 3.共同要实现的接口
* 注意:
* 代理对象代理真实角色去结婚,真实结婚的还是真实对象。
* 优点:
* 代理对象可以做很多真实对象做不了的事情,真实对象专心的去做自己的事情
*/
public class StaticProxy {
public static void main(String[] args) {
//结婚,让代理帮你,至于要将你作为对象交给代理对象,它就可以帮你完成结婚
//获取真实角色
You you = new You();
//获取代理角色,并将真实角色传给代理角色
WeddingCompany weddingCompany = new WeddingCompany(you);
//代理觉得帮你去结婚,实际上还是你自己去结婚的,不过结婚所附带的是就不用你去做了,你只需要专注结婚,其他的事情代理帮你做好
weddingCompany.happyMarry();
}
}
//你
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("你要结婚了");
}
}
//你的代理对象:婚庆公司
class WeddingCompany implements Marry{
//婚庆公司需要你这个人,所以将you对象组合进来
private You you;
public WeddingCompany(You you) {
this.you = you;
}
@Override
public void happyMarry() {
//结婚之前代理帮真实角色做的事
System.out.println("结婚之前,布置现场");
//真实角色只用专注于结婚就行了
you.happyMarry();
//结婚之后代理帮真实角色做的事
System.out.println("结婚之后,惨不忍睹");
}
}
//你们都要做的事(接口):结婚
interface Marry{
void happyMarry();
}
这就是简单的实现了静态代理模式,在我们多线程的第二种创建方式(实现Runnable接口)中就体现了静态代理模式的思想。
那么静态代理有什么好处呢?
- 使用静态代理模式可以让真实角色认认真真的完成自己的工作,更加纯粹,不去关注一些公共的事情
- 公共业务需要由代理对象来实现,实现了业务的分工,体现了解耦的思想
- 公共业务需要扩展的话非常的方便
那么静态代理又有哪些缺点?
- 如果真实角色有很多,那么代理角色的工作量就相当的大了,开发效率就会变得很低
那么动态代理就来了…
三、动态代理
动态代理和静态代理的角色都是一样的,唯一的区别就是静态代理模式的代理类(婚庆公司)是我们提前写好的,但是动态代理的代理类是动态生成的。
动态代理分为两大类:
- 基于JDK原生态的接口实现
- 基于类实现
如:CGLIB、Javassist、ASM等
其中用的比较多的是Javassist来生成动态代理。
那么我们了解动态代理之前需要掌握两个类:
- InvocationHandler:
InbocationHandler类是由代理实例调用处理程序实现的接口。
invoke(Object proxy,方法 method,Object[] args)方法处理代理实例上的方法调用并返回结果。 - Proxy:
Proxy提供了创建动态代理类和实力的静态发方法,他也是由这些方法创建的所有动态代理类的超类。
newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)方法返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
代码实现动态代理:
一个共同的接口:结婚
package com.muhan.proxy;
//共同的接口:结婚
public interface Marry {
//结婚
void happyMarry();
}
真实角色:you
package com.muhan.proxy;
//真实角色:你,实现共同结婚接口
public class You implements Marry{
//结婚
public void happyMarry() {
System.out.println("你结婚了");
}
}
代理角色(动态生成)
package com.muhan.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理类生成的接口对象
public class WeddingCompany implements InvocationHandler {
//维护一个真实角色的引用
private Object realObject;
public void setYou(Object realObject) {
this.realObject = realObject;
}
//动态生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
realObject.getClass().getInterfaces(),this);
}
//proxy:代理类;method:代理类的调用处理程序方法的对象
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeOfMarry();
Object result = method.invoke(realObject, args);
afterOfMarry();
return result;
}
//结婚前婚庆公司帮你做的事
private void beforeOfMarry() {
System.out.println("布置婚礼现场");
}
//结婚后婚庆公司帮你做的事
private void afterOfMarry() {
System.out.println("制作录像剪辑视频");
}
}
测试类:
package com.muhan.proxy;
public class ProxyTest {
public static void main(String[] args) {
//创建一个真实角色
You you = new You();
//创建一个动态代理角色
WeddingCompany weddingCompany = new WeddingCompany();
//将真实角色交给代理角色
weddingCompany.setYou(you);
//代理角色代理真实角色结婚
Marry proxy = (Marry) weddingCompany.getProxy();
proxy.happyMarry();
}
}
结果:
动态代理的好处:
- 可以使真实角色专注于做自己的事情,不用去关注一些公共的事情
- 公共的业务由代理来完成,实现业务的分工
- 公共业务需要扩展的话,可以更加集中和方便
- 一个动态代理一般代理一类业务,一个动态理;也可以代理多个类、接口