文章目录
。
提示:以下是本篇文章正文内容,下面案例可供参考
一、预备知识-动态代理
1.1什么是代理
顾客:要调用方法的人;也就是我们的服务对象,它不关系商家实现请求的过程,它只关心结果;
商家:相当于一个代理商,它有着和厂家一模一样的方法,
厂家:它内部存储我们要调用的方法,但是顾客不能直接调用,
当顾客打算调用厂家的方法时,顾客先把请求转发给商家,
商家把顾客的请求发给厂家,厂家收到请求后把内部方法给到商家,商家再把方法给回顾客;
这个过程就叫代理;
在商家转发请求给厂家之前,如果商家加一些自己的条件和附加值给顾客,这叫前置通知
在商家收到厂家返回的请求之后,如果商家加一些自己的条件和附加值给顾客,这叫后置通知;
如果说商家在转发和返回请求过程中都添加了条件和给顾客,那这个就叫环绕通知;
前面讲了什么是代理,那我们继续来讲什么是动态代理;在代理过程中,如果这个商家是由系统在启动的时候自动创建的,在jdk中专门有一个类帮我们生成这些商家,在系统启动的过程中我们会告诉系统我们需要哪些类和需求;
1.3基于jdk动态代理实现
在基于JDK的动态代理的实现中有两个重要的类:avocettionHenoles, proxy
InvocationHandler
是代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke方法。
ProXy
JDK中动态生成代理类的工具类一个动态代理的示例:
定义一个接口(基于JDK的动态代理只能使用接口)
public interface ISubject {
void hello(String param);
}
为接口定义实现类
public class SubjectImpl implements ISubject {
@Override
public void hello(String param) {
System.out.println("hello " + param);
}
}
实现一个代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
//目标类代理对象
private Object target;
//代理
public JDKProxy(Object target) {
this.target = target;
}
//动态生成代理的过程
public Object newProxy() {
return (ISubject)Proxy.newProxyInstance(
target.getClass().getClassLoader(),//通过 target获取到加载的这个类
target.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("---------- 在业务方法调用之前可以进行前置增强 ------------");
//利用反射机制调用方法,invoke为返回值,如果没有返回null
Object invoke = method.invoke(target, args);
System.out.println("---------- 在业务方法调用之前可以进行后置增强 ------------");
return invoke;
}
}
public class DKProxyDemo {
public static void main(String[] args) {
ISubject subject = new SubjectImpl();
JDKProxy subjectProxy = new JDKProxy(subject);
ISubject proxy = (ISubject)subjectProxy.newProxy();
proxy.hello("yy");
}
}
二、AOP
2.1基本概念
- 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出.
- 目标(Target):被通知(被代理)的对象,如上例 中的SubjectImpl
- 通知(Advice):在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理),也可以理解为AOP真正要实现的功能
- 代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知),请注意:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的,如上例 中的JDKProxy
- 切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点。(也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)
- 适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut)
AOP运行原理:目标对象只负责业务逻辑,通知只负责AOP增强逻辑(如日志,数据验证等),而代理对象则将业务逻辑而AOP增强代码组织起来(组织者)
2.2AOP带来的好处
AOP是公用的框架代码放置的理想地方,将公共代码与业务代码分离,使我们在处理业务时可以专心的处理业务。
三、Spring AOP
在spring中org.springframework.aop.framework.ProxyFactoryBean用来创建代理对象,在一般情况下它需要注入一下三个属性:
proxylnterfaces 代理应该实现的接口列表(List)
interceptorNames 需要应用到目标对象上的通知Bean的名字·
target 目标对象 (Object)
准备工作:创建一个IBookService接口及其实现类,用于演示spring AOP开发示例:
代码如下(示例):
public interface IBookService {
// 购书
public boolean buy(String userName, String bookName, Double price);
// 发表书评
public void comment(String userName, String comments);
}
public class BookServiceImpl implements IBookService {
public boolean buy(String userName, String bookName, Double price) {
//logger.info("userName={},bookName={},price={}", userName, bookName, price);
// 通过控制台的输出方式模拟购书
System.out.println(userName + " buy " + bookName + ", spend " + price);
return true;
}
public void comment(String userName, String comments) {
System.out.println(userName + " say:" + comments);
}
}