知识点-SpringAOP

转自:微信公众号-Java帮帮-20190118

Spring AOP是什么?

我们知道Java是一个面向对象(OOP)的语言,但它有一些弊端,比如当我们需要为多个不具有继承关系的对象引入一个公共行为,例如日志、权限验证、事务等功能时,只能在在每个对象里引用公共行为。这种方式不利于长期维护,且会造成大量重复代码,AOP就可以来弥补OOP的不足,

  1. 代理模式

比如A对象要做一件事情,在没有代理前,自己来做;在对 A 代理后,由 A 的代理类 B 来做。代理其实是在原实例前后加了一层处理,这也是 AOP 的初级轮廓。

  1. 静态代理原理及实践

静态代理就是在程序运行前就已经存在代理类的字节码文件、代理类和原始类的关系在运行前就已经确定
比如:

// 接口
public interface IUserDao {
void save();
void find();
}

// 目标对象
class UserDao implements IUserDao{
@Override
public void save() {
System.out.println(“模拟:保存用户!”);
}
@Override
public void find() {
System.out.println(“模拟:查询用户”);
}
}

/**
*静态代理
*/
class UserDaoProxy implements IUserDao{
// 代理对象,需要维护一个目标对象
private IUserDao target = new UserDao();
@Override
public void save() {
System.out.println(“代理操作: 开启事务…”);
target.save(); // 执行目标对象的方法
System.out.println(“代理操作:提交事务…”);
}
@Override
public void find() {
target.find();
}
}
特点:目标对象必须实现接口、 代理对象要和目标对象实现一样的接口

静态代理保证了业务类只关注逻辑本身,代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,就需要为每一种方法都进行代理,而且如果要增加一个方法,除了实现类需要实现这个方法,所有的代理类也要实现此方法。

  1. 动态代理
    动态代理的源码是在程序运行期间,通过JVM反射等机制动态生成,代理类和委托类是关系是在运行时才确定的。

// 接口
public interface IUserDao {
void save();
void find();
}

//目标对象
class UserDao implements IUserDao{
@Override
public void save() {
System.out.println(“模拟: 保存用户!”);
}
@Override
public void find() {
System.out.println(“查询”);
}
}

动态代理:代理工厂,给多个目标对象生成代理对象!

class ProxyFactory{

// 接收一个目标对象
private Object target;

public ProxyFactory(Object target) {
    this.target = target;
}

// 返回对目标对象(target)代理后的对象(proxy)
public Object getProxyInstance() {
    Object proxy = Proxy.newProxyInstance(
        target.getClass().getClassLoader(),  // 目标对象使用的类加载器
        target.getClass().getInterfaces(),   // 目标对象实现的所有接口
        new InvocationHandler() {            // 执行代理对象方法时候触发

            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {

                // 获取当前执行的方法的方法名
                String methodName = method.getName();
                // 方法返回值
                Object result = null;
                if ("find".equals(methodName)) {
                    // 直接调用目标对象方法
                    result = method.invoke(target, args);
                } else {
                    System.out.println("开启事务...");
                    // 执行目标对象方法
                    result = method.invoke(target, args);
                    System.out.println("提交事务...");
                }
                return result;
            }
        }
    );
    return proxy;
}
}

动态代理(动态代理也叫JDK代理或接口代理)
IUserDao proxy = (IUserDao)new ProxyFactory(target).getProxyInstance();
其实是 JDK 动态生成了一个类去实现接口,隐藏了这个过程:
class $jdkProxy implements IUserDao{}
使用 JDK 生成的动态代理的前提是目标类必须有实现的接口。但这里又引入一个问题,如果某个类没有实现接口,就不能使用 JDK 动态代理。所以 CGLIB 代理就是解决这个问题的。

CGLIB 是以动态生成的子类继承目标的方式实现,在运行期动态的在内存中构建一个子类,如下:

public class UserDao{}
// CGLIB 是以动态生成的子类继承目标的方式实现,程序执行时,隐藏了下面的过程
public class $Cglib_Proxy_class extends UserDao{}
CGLIB 使用的前提是目标类不能为 final 修饰。因为 final 修饰的类不能被继承。

现在,我们可以看看 AOP 的定义:面向切面编程,核心原理是使用动态代理模式在方法执行前后或出现异常时加入相关逻辑。

通过定义和前面代码我们可以发现3点:

AOP 是基于动态代理模式。
AOP 是方法级别的。
AOP 可以分离业务代码和关注点代码(重复代码),在执行业务代码时,动态的注入关注点代码。切面就是关注点代码形成的类。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值