Spring AOP原理及 *
作者:IT小郭. 发布时间:2023-06-19 18:59:56
一、什么是代理?
指为一个目标对象提供一个代理对象, 并由代理对象控制对目标对象的引用. 使用代理对象, 是为了在不修改目标对象的基础上,增强目标对象的业务逻辑.
1、静态代理
静态代理的特点是, 为每一个业务增强都提供一个代理类, 由代理类来创建代理对象. 下面我们通过静态代理来实现对转账业务进行身份验证.
(1) 转账业务
public interface IAccountService {
//主业务逻辑: 转账
void transfer();
}
public class AccountServiceImpl implements IAccountService {
@Override
public void transfer() {
System.out.println("调用dao层,完成转账主业务.");
}
}
(2) 代理类
public class AccountProxy implements IAccountService {
//目标对象
private IAccountService target;
public AccountProxy(IAccountService target) {
this.target = target;
}
/**
* 代理方法,实现对目标方法的功能增强
*/
@Override
public void transfer() {
before();
target.transfer();
}
/**
* 前置增强
*/
private void before() {
System.out.println("对转账人身份进行验证.");
}
}
(3) 测试
public class Client {
public static void main(String[] args) {
//创建目标对象
IAccountService target = new AccountServiceImpl();
//创建代理对象
AccountProxy proxy = new AccountProxy(target);
proxy.transfer();
}
}
结果: 对转账人身份进行验证.调用dao层,完成转账主业务.
2、 *
静态代理会为每一个业务增强都提供一个代理类, 由代理类来创建代理对象, 而 * 并不存在代理类, 代理对象直接由代理生成工具动态生成.
2.1、JDK *
JDK * 是使用 java.lang.reflect 包下的代理类来实现. JDK * * 必须要有接口.
(1) 转账业务
public interface IAccountService {
//主业务逻辑: 转账
void transfer();
}
public class AccountServiceImpl implements IAccountService {
@Override
public void transfer() {
System.out.println("调用dao层,完成转账主业务.");
}
}
(2) 增强
因为这里没有配置切入点, 称为切面会有点奇怪, 所以称为增强.
public class AccountAdvice implements InvocationHandler {
//目标对象
private IAccountService target;
public AccountAdvice(IAccountService target) {
this.target = target;
}
/**
* 代理方法, 每次调用目标方法时都会进到这里
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
return method.invoke(target, args);
}
/**
* 前置增强
*/
private void before() {
System.out.println("对转账人身份进行验证.");
}
}
(3) 测试
public class Client {
public static void main(String[] args) {
//创建目标对象
IAccountService target = new AccountServiceImpl();
//创建代理对象
IAccountService proxy = (IAccountService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new AccountAdvice(target)
);
proxy.transfer();
}
}
结果: 对转账人身份进行验证.调用dao层,完成转账主业务.
2.2、 CGLIB
*
JDK * 必须要有接口, 但如果要代理一个没有接口的类该怎么办呢? 这时我们可以使用CGLIB * . CGLIB * 的原理是生成目标类的子类, 这个子类对象就是代理对象, 代理对象是被增强过的.
注意: 不管有没有接口都可以使用CGLIB * , 而不是只有在无接口的情况下才能使用
(1) 转账业务
public class AccountService {
public void transfer() {
System.out.println("调用dao层,完成转账主业务.");
}
}
(2) 增强
因为这里没有配置切入点, 称为切面会有点奇怪, 所以称为增强.
public class AccountAdvice implements MethodInterceptor {
/**
* 代理方法, 每次调用目标方法时都会进到这里
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
before();
return methodProxy.invokeSuper(obj, args);
// return method.invoke(obj, args); 这种也行
}
/**
* 前置增强
*/
private void before() {
System.out.println("对转账人身份进行验证.");
}
}
(3) 测试
public class Client {
public static void main(String[] args) {
//创建目标对象
AccountService target = new AccountService();
//
//创建代理对象
AccountService proxy = (AccountService) Enhancer.create(target.getClass(),
new AccountAdvice());
proxy.transfer();
}
}
结果: 对转账人身份进行验证.调用dao层,完成转账主业务.
二、模拟Spring AOP场景
了解了 * 后, 我们就可以自己来实现Spring AOP功能了, 所以下面我们来模拟下Spring AOP场景.
(1) 转账业务
public interface IAccountService {
//主业务逻辑: 转账
void transfer();
}
public class AccountServiceImpl implements IAccountService {
@Override
public void transfer() {
System.out.println("调用dao层,完成转账主业务.");
}
}
(2) 切面抽象类
定义一个切面抽象类, 该类使用了模板方法的设计模式, 为开始, 结束, 异常, 前置增强, 后置增强提供了默认实现, 当我们定义切面类时只需要按需重写它们就行. isIntercept() 方法用来判断切入点是否正确, 切面类需要重写这个方法.
public abstract class BaseAspect implements MethodInterceptor {
private static final Logger logger = LoggerFactory.getLogger(BaseAspect.class);
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object result = null;
begin();
try {
if (isIntercept(method, args)) {
before();
result = methodProxy.invokeSuper(obj, args);
after();
} else {
result = methodProxy.invokeSuper(obj,args);
}
} catch (Exception e) {
logger.error("proxy failure", e);
error(e);
throw e;
} finally {
end();
}
return result;
}
/**
* 开始增强
*/
public void begin() {
}
/**
* 切入点判断
*/
public boolean isIntercept(Method method, Object[] args) throws Throwable {
return true;
}
/**
* 前置增强
*/
public void before() throws Throwable {
}
/**
* 后置增强
*/
public void after() throws Throwable {
}
/**
* 异常增强
*/
public void error(Throwable e) {
}
/**
* 最终增强
*/
public void end() {
}
}
(3) 切面类
创建一个切面类, 类中配置切入点和增强.
public class AccountAspect extends BaseAspect {
/**
* 切入点
*/
public boolean isIntercept(Method method, Object[] args) throws Throwable {
return method.getName().equals("transfer");
}
/**
* 前置增强
*/
public void before() throws Throwable {
System.out.println("对转账人身份进行验证.");
}
}
(4) 代理工厂类
定义一个工厂类来创建代理, 其实不创建这个类也行, 但为了模仿Spring还是创建了. @SuppressWarnings是为了抑制警告, 就是编译器上面的黄线.
public class ProxyFactory {
@SuppressWarnings("unchecked")
public static <T> T createProxy(final Class<?> targetClass, final MethodInterceptor methodInterceptor) {
return (T) Enhancer.create(targetClass,methodInterceptor);
}
}
(5) 测试
public class Client {
public static void main(String[] args) {
//创建目标对象
IAccountService target = new AccountServiceImpl();
//切面
BaseAspect accountAspect = new AccountAspect();
//创建代理对象
IAccountService proxy = (IAccountService) ProxyFactory.createProxy(target.getClass(), accountAspect);
proxy.transfer();
}
}
结果:对转账人身份进行验证.调用dao层,完成转账主业务.
来源:https://blog.csdn.net/GoodburghCottage/article/details/126931618


猜你喜欢
- 使用System.Environment获取电脑的相关属性,入门案例,具体内容如下static void Main(string[] arg
- Framework如何实现Binder为了日常的使用framework层同样实现了一套binder的接口。可以肯定的是framework使用
- 一、JAVA常用APIjava.lang.Math提供sin, cos, tan, exp, log, log10 等类方法,PI和E等类字
- 前言可能有人会有疑问,为什么外面已经有更好的组件,为什么还要重复的造轮子,只能说,别人的永远是别人的,自己不去造一下,就只能知其然,而不知其
- 前言gradle的定义(来自 * )Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一
- 本文较为详细的分析了Java反射机制。分享给大家供大家参考,具体如下:一、预先需要掌握的知识(java虚拟机) java虚拟机的方法区:ja
- 本文实例为大家分享了Android优酷圆形菜单的具体代码,供大家参考,具体内容如下先来看看效果:首先来分析一下:这个菜单可以分成三个菜单:1
- 这里主要利用API函数Animate Window实现窗体左右,上下,扩展,淡入滑动或滚动动画效果,步骤如下:1.新建窗体,使用2个Grou
- 一、前言android客户端开发进入尾声,负责SEO同事突然发给我一个涉及45个发布渠道的噩耗,之前只发布自有渠道的工作方式(手动修改参数打
- C#之委托委托:顾名思义,让别人帮你办件事。委托是C#实现回调函数的一种机制。可能有人会问了,回调函数是个啥???举个例子:我现在是一家公司
- 本文实例讲述了C#实现简单的Login窗口。分享给大家供大家参考。具体实现方法如下:C# 制作登录窗体,登录成功之后正确的做法是关闭(clo
- 在为什么阿里巴巴不建议在for循环中使用”+”进行字符串拼接一文中,我们介绍了几种Java中字符串拼接的方式,以及优缺点。其中还有一个重要的
- 网上对于这样的功能已经是泛滥成河了,但是最近遇到这样的一个需求,还是要值得我们学习一下,并将他记录下来。布局文件:<FrameLayo
- 本文汇总了几个WinForm中常见的实用技巧,对于C#程序开发有着很好的参考借鉴价值。具体分析如下:一、屏蔽窗体右上角关闭按钮1.重写OnC
- 1.引入AOP依赖<dependency>
- 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。比如说,你的代码少了一个分号,那么运行出来结果是提示是错误
- 这篇文章主要介绍了java泛型常用通配符实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以
- 一、Java中锁的概念自旋锁:是指当一个线程获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能被成功获取,
- 本文实例为大家解析了Zxing生成二维码的经典案例,供大家参考,具体内容如下1、首先呢,先编译 compile ‘com.google.zx
- 作者:sparkdev出处:http://www.cnblogs.com/sparkdev/注意,本文所说的断点续传特指 HTTP 协议中的