【SSM - Spring篇04】AOP面向切面编程 - 代理模式 - jdbc动态代理 -CGLIB动态代理

AOP概念

  AOP采取横向抽取机制,即将分散在各个方法中的重复代码提取出来,然后在程序编译或运行阶段,再将这些抽取出来的代码应用到需要执行的地方(一般用于日志记录、性能统计、安全控制、事务处理、异常处理等操作)

AOP术语

  1. 切面
      切面(Aspect)是指封装横切到系统功能(如事务处理)的类。
  2. 连接点
      连接点(Joinpoint)是指程序运行中的一些时间点,如方法的调用或异常的抛出。
  3. 切入点
      切入点(Pointcut)是指那些需要处理的连接点。在Spring AOP 中,所有的方法执行都是连接点,而切入点是一个描述信息,它修饰的是连接点,通过切入点确定哪些连接点需要被处理。
  4. 通知(增强处理)
      由切面添加到特定的连接点(满足切入点规则)的一段代码,即在定义好的切入点处所要执行的程序代码。可以将其理解为切面开启后,切面的方法。因此,通知是切面的具体实现。
  5. 引入
      引入(Introduction)允许在现有的实现类中添加自定义的方法和属性。
  6. 目标对象
      目标对象(Target Object)是指所有被通知的对象。如果AOP 框架使用运行时代理的方式(动态的AOP)来实现切面,那么通知对象总是一个代理对象。
  7. 代理
      代理(Proxy)是通知应用到目标对象之后,被动态创建的对象。
  8. 组入
      组入(Weaving)是将切面代码插入到目标对象上,从而生成代理对象的过程。根据不同的实现技术,AOP织入有三种方式:编译器织入,需要有特殊的Java编译器;类装载期织入,需要有特殊的类装载器;动态代理织入,在运行期为目标类添加通知生成子类的方式。Spring AOP框架默认采用动态代理织入,而AspectJ(基于Java语言的AOP框架)采用编译器织入和类装载期织入。



代理模式(就好比中介的存在)

代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。(添加额外的功能)

(虚拟)代理

  虚拟代理就是作为创建开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候才创建它。当对象在创建前和创建中的时候,由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求直接委托给对象。
在这里插入图片描述



静态代理

  需要显式的实现与目标对象类(RealSubject)相同的接口,在程序运行前,代理类就已经创建好了。

案例实现

  1. 创建被代理类的接口和接口的实现
public interface Math {
    
    
    public int jia(int a, int b);//加
    public int jian(int a, int b);//减
}
public class MathImpl implements Math{
    
    

    public int jia(int a,int b){
    
    
        return a+b;
    }
    public int jian(int a,int b){
    
    
        return a-b;
    }
}
  1. 创建工具类,实现共有方法
public class Tools {
    
    

    public void check(){
    
    
        System.out.println("权限检查......");
    }
    public void log(){
    
    
        System.out.println("日志记录......");
    }

}

  1. 创建代理类
public class MathProxy implements Math {
    
    

//    MathImpl mathImpl = new MathImpl();  //业务逻辑
//    Tools tools = new Tools();  //工具类
    MathImpl mathImpl;  //业务逻辑
    Tools tools;  //工具类

//    public MathProxy(){}
    public MathProxy(MathImpl mathImpl, Tools tools) {
    
    
    	//在构造器中直接初始化了
        this.mathImpl = mathImpl;
        this.tools = tools;
    }

    @Override
    public int jia(int a, int b) {
    
    
        tools.check();
        int result = mathImpl.jia(a,b);
        tools.log();
        return result;
    }

    @Override
    public int jian(int a, int b) {
    
    
        tools.check();
        tools.log();
        return mathImpl.jian(a,b);
    }
}
  1. 创建测试类
public class Test {
    
    

    public static void main(String[] args) {
    
    
        /* 被代理对象--业务类 数学计算类 */
        MathImpl mathImpl = new MathImpl();
		//创建工具类
        Tools tools = new Tools();
        
//      代理对象
        Math math = new MathProxy(mathImpl,tools);
        int result1 = math.jia(2,6);
        System.out.println(result1);
        
        int result2 = math.jia(3,2);
		System.out.println(result2);
    }
}

  1. 运行结果

在这里插入图片描述



动态代理(Spring AOP中常用JDK和CGLIB动态代理 - 现在一般用aspectj)

  不需要显式实现与目标对象类(RealSubject)相同的接口,而是将这种实现推迟到程序运行时由 JVM来实现。动态代理在需要的时候才去创建,而不是提前创建好

JDK和CGLIB动态代理的主要区别:

JDK动态代理只能针对实现了接口的类的接口方法进行代理
CGLIB动态代理基于继承来实现代理,所以无法对final类、private方法和static方法实现代理

Spring AOP中的代理使用的默认策略是:

如果目标对象实现了接口,则默认采用JDK动态代理
如果目标对象没有实现接口,则采用CgLib进行动态代理
如果目标对象实现了接口,且强制CgLib代理,则采用CgLib进行动态代理


1. JDK动态代理实现Spring AOP

  JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象。因此,对于使用业务接口的类,Spring默认使用JDK动态代理实现AOP
  在Spring中默认使用JDK动态代理实现AOP编程。使用org.springframework.aop.framework.ProxyFactoryBean创建代理是Spring AOP实现的最基本方式。

案例实现

  1. 创建被代理类的接口及实现类
public interface UserDao {
    
    
    public void save(String name);  //保存
    public void delete();           //删除
}
//被代理类
public class UserDaoImpl implements UserDao{
    
    
    @Override
    public void save(String name) {
    
    
        System.out.println("保存用户成功 :"+name);
    }

    @Override
    public void delete() {
    
    
        System.out.println("删除用户成功:");
    }
}
  1. 创建切面类(公共方法)
//切面类:定义公共方法
public class MyAspect {
    
    
    public void check(){
    
    
        System.out.println("check user......正在查找用户");
    }

    public void log(){
    
    
        System.out.println("logging.....正在记录日志");
    }
}
  1. 创建代理类
//代理类
public class MyProxy implements InvocationHandler {
    
    

    private UserDao userDao;    //被代理类
    private MyAspect myAspect;  //切面类 -- 定义公共方法

    public MyProxy(UserDao userDao, MyAspect myAspect) {
    
    
        this.userDao = userDao;
        this.myAspect = myAspect;
    }

    //创建代理对象
    public Object create(){
    
    
        ClassLoader classLoader = userDao.getClass().getClassLoader();
//      Class<?>[] interfaces  被代理对象的实现接口
        Class<?>[] interfaces = userDao.getClass().getInterfaces();
        UserDao proxy = (UserDao) Proxy.newProxyInstance(classLoader,interfaces,this);
        System.out.println("创建代理对象create");
        return proxy;
    }

//    调用方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
//        织入 advice 加入到 被代理对象方法之前或之后
//        method就是调用的被代理对象的方法
        String methodName = method.getName();
//        Object 被代理对象
//        调用方法
        System.out.println("调用invoke方法");
        myAspect.check();//调用切面方法
        method.invoke(userDao,args);//userDaoImpl.save(参数)
        myAspect.log();//调用切面方法
        return null;
    }
}
  1. 创建测试类
public class Test {
    
    
    public static void main(String[] args) {
    
    
//      被代理类
        UserDao userDao = new UserDaoImpl();
//      切面
        MyAspect myAspect = new MyAspect();

        //创建代理类  参1:被代理类  参2:切面(公共方法)
        MyProxy myProxy = new MyProxy(userDao,myAspect);
        //通过代理类来创建实例 - 代理对象
        UserDao proxy = (UserDao)myProxy.create();
        proxy.save("GF_浪夏一学");
        proxy.delete();
    }
}
  1. 运行结果

在这里插入图片描述


2. CGLIB动态代理实现Spring AOP

  CGLIB(Code Generation Library)是一个高性能开源的代码生成包,采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。在Spring Core包中已经集成了CGLIB所需要的JAR包,不需要另外导入JAR包

案例实现

  1. 创建被代理类(目标类)
public class UserService {
    
    
    public void save(){
    
    
        System.out.println("save service ......");
    }
    public void delete(){
    
    
        System.out.println("delete service ......");
    }
}
  1. 创建切面类(公共方法)
public class MyAspect {
    
    

    public void check(){
    
    
        System.out.println("check方法......检查包");
    }

    public void log(){
    
    
        System.out.println("logging方法......记录日志");
    }
}
  1. 创建代理类
public class MyProxy<T> implements MethodInterceptor {
    
    

    private T byProxy;          //被代理类
    private MyAspect myAspect;  //切面

    public MyProxy(T byProxy, MyAspect myAspect) {
    
    
        this.byProxy = byProxy;
        this.myAspect = myAspect;
    }

//    创建代理对象
    public T create(){
    
    
        // 通国Enhancer创建代理类 ----  Proxy
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(byProxy.getClass());
        enhancer.setCallback(this);//实现MethodInterceptor接口的对象,就是当前对象
        T proxy = (T)enhancer.create();
        return proxy;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    

//        Method method,调用的被代理对象方法
        String methodName = method.getName();
        if(methodName.equals("save")){
    
    
            myAspect.check();
            method.invoke(byProxy,objects);
            myAspect.log();
        }
        if(methodName.equals("delete")){
    
    
            myAspect.check();
            method.invoke(byProxy,objects);
            myAspect.log();
        }
        return null;
    }
}

  1. 创建测试类
public class CGLIBTest {
    
    
    public static void main(String[] args) {
    
    
//       被代理对象
        UserService userService = new UserService();
        MyAspect myAspect = new MyAspect();

        //创建代理对象
        MyProxy myProxy = new MyProxy(userService,myAspect);
        //通过代理类创建被代理对象
        UserService service = (UserService)myProxy.create();

        //调用方法
        service.save();
        service.delete();
    }
}
  1. 运行结果
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40542534/article/details/108683231
今日推荐