暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring AOP之代理模式

产教Code 2019-08-17
140

SpringAop第一节

学过spring的同学应该都知道AOP,AOP(Aspect Oriented Programming )是OOP的延续,其本意就是面向切面编程。并不是全部的Aop框架都是一样的,他们的连接点模型的功能可能有强弱之分,有些可以在字段,方法,构造函数级别的,有些只能是方法的比如Spring Aop。目前市面上最主要的Aop框架有:Spring AOP
AspectJ
JbossAOP
后两种都可以对字段、方法、构造函数支持。

Spring AOP和Aspect有着大量的协作。

AOP最常见的应用场景:Spring的事务管理、记录日志

Spring对Aop支持的四种情况:

  • 经典的基于代理的Aop

  • @AspectJ注解驱动的切面

  • 纯pojo切面

  • 注入式AspectJ

对于Aop来说有几个关键的名词:

Aspect(切面)
:Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

Joint point(连接点)
:表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。

Pointcut(切点)
:表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。

Advice(增强)
:Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

Target(目标对象)
:织入 Advice 的目标对象。

这里就不给大家写AOP例子了.

大家应该也知道Spring AOP是利用代理技术实现的但是我们真的了解代理吗?

代理: 静态代理

动态代理: jdk动态代理

    cglib动态代理

接下来我们先来将静态代理 :

首先我们定义一个接口:

package staticProxy.inte;
/**
* @program: Proxy
* @description:
* @author: LHD QQ:1727865856
* @create: 2019-08-15 23:32
**/
public interface ISinger {
//歌手唱歌的方法
void singing();
}

我们为这个接口创建一个实现类:

package staticProxy.impl;


import staticProxy.inte.ISinger;


/**
* @program: Proxy
* @description:
* @author: LHD QQ:1727865856
* @create: 2019-08-15 23:33
**/
public class SuperSinger implements ISinger {
@Override
public void singing() {
//实现了歌手唱歌
System.out.println("歌手在唱歌!");
}
}

接下来我们来创建一个代理类:

package staticProxy.proxy;


import staticProxy.impl.SuperSinger;
import staticProxy.inte.ISinger;


/**
* @program: Proxy
* @description:
* @author: LHD QQ:1727865856
* @create: 2019-08-15 23:33
**/
public class Handler implements ISinger {
//具体类型的对象
private SuperSinger superSinger;
//有参构造当我们实例化这个类的时候穿进来一个“本体对象”
public Handler(SuperSinger superSinger) {
this.superSinger = superSinger;
}


@Override
public void singing() {
//对本体对象做前置增强
System.out.println("before....");
if (superSinger!=null){
superSinger.singing();
}
//对本地对象做后置增强
System.out.println("after....");
}
}




//测试类
public class Test {
public static void main(String[] args) {
//实例化一个本体
SuperSinger superSinger=new SuperSinger();
//实例化一个代理类,将本体当做参数传入
Handler handler=new Handler(superSinger);
//调用代理类的singing方法-->间接的调用了我们本体类的singing方法
handler.singing();
}
}

运行结果如下:


这串代码大家可以看得懂吗?看不懂的话可以在群里面讨论一下.

我们会发现代理类也实现了我们定义的接口,那么我们如果要想改接口的话我们是不是实现类(也就是上述的本体)和代理类都要改。并且静态代理的代理类在实现代理之前就得知道它要具体代理那个对象,这种情况就很麻烦了。但是我们还是想使用代理怎么办。-->动态代理

jdk代理:

上面说过动态代理分为两种方式实现:


一样首先我们创建接口:

package com.inte;


/**
* @program: Proxy
* @description:
* @author: LHD QQ:1727865856
* @create: 2019-08-15 14:35
**/
public interface ISinger {


void sing();
}

实现接口:

package com.impl;


import com.inte.ISinger;


/**
* @program: Proxy
* @description:
* @author: LHD QQ:1727865856
* @create: 2019-08-15 14:36
**/
public class SuperSinger implements ISinger {
@Override
public void sing() {
System.out.println("歌手唱歌!");
}
}

创建代理类:

package com.impl;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;


/**
* @program: Proxy
* @description:
* @author: LHD QQ:1727865856
* @create: 2019-08-15 14:36
**/
//注意此时我们的代理类实现了jdk的InvocationHandler接口实现类invoke方法
public class Hander implements InvocationHandler {
//Object类型的对象
private Object o;


public Hander(Object o) {
this.o = o;
}


// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("befor....");
//执行本体要执行的方法
Object invoke = method.invoke(o, args);
System.out.println("after....");
//返回一个代理对象
return invoke;
}
}


//测试类
public void test{
public static void main(String [] args){
//创建一个本体对象
SuperSinger superSinger = new SuperSinger();
//为代理类创建一个对象
ISinger iSinger =
(ISinger) Proxy.newProxyInstance(Main.class.getClassLoader(), SuperSinger.class.getInterfaces(), new Hander(superSinger));
iSinger.sing();
}
}

执行结果和静态代理相同

上面我们说实例化代理对象用到了方法

   @CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)

第一个参数ClassLoder:

这是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。

第二个参数:

Class<?>[] interfaces 本体类实现的接口通过 SuperSinger.class.getInterfaces()获取

第三个参数:

代理类 




 接下来讲下利用cglib来实现动态代理


接口->实现类这里就不写了。


//测试cglib动态代理方法,这里我们就可以不写代理类了。
public static void CGLB() {
//本体类也称委托类
SuperSinger superSinger = new SuperSinger();
//利用cglib为你产生的代理类
// 创建代理类使用Enhancer类的public static Object create(Class type, Callback callback) 方法
// type:就是本体类,callback:就是实现代理的形式(我们这里使用它的实现类 InvocationHandler)
SuperSinger superSinger1 = (SuperSinger) Enhancer.create(SuperSinger.class, new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("befo.....模拟在方法运行前做的处理");
//让我们调用的方法继续往下执行
Object invoke = method.invoke(superSinger, objects);
System.out.println("after....模拟在方法运行后做的一些处理");
//返回的代理类
return invoke;
}
});
//使用代理类调用本体方法
superSinger1.sing();
}


看不懂的群里讨论。第一次发布博文过于紧张可能有的东西没想起来。望大家多发表意见我们会更加努力为大家提供更好的博文。以上代码有错误请尽管提出。


文章转载自产教Code,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论