Java代理模式,了解SpringAOP动态代理和静态代理

代理模式

产生原因:

service层:业务处理层

业务处理层于事务控制紧紧耦合在一起,代码冗余,不便于大批量开发

1.代理模式

1).组成部分
1.要求代理者实现与被代理者相同的接口
2.在代理方法中实现功能的扩展
3.用户调用代理对象完成功能(用户认为代理就是目标对象)

在这里插入图片描述

1.2 静态代理

1.2.1 通过代理模式实现事务控制

角色划分:
1.目标对象target UserServiceImpl类
2.目标方法 method addUser()方法
3.代理: 实现事务控制.
4.代理对象与目标对象实现相同的接口

1.2.2 修改目标对象名称

在这里插入图片描述

1.2.3 编辑代理类
@Service("userService")
public class StaticProxy implements UserService {

    //要求引入目标对象
    @Autowired //ByType  byName
    //@Qualifier("target")
    private UserService target;

    //目的: 对原有方法进行扩展
    @Override
    public void addUser(User user) {
        try {
            System.out.println("事务开始");
            target.addUser(user);
            System.out.println("事务结束");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("事务回滚");
        }
    }
}
1.2.4 编辑测试类
@Test
public void testStaticProxy(){
    ApplicationContext context =
            new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService = (UserService) context.getBean("userService");
    User user = new User();
    user.setId(10001);
    user.setName("测试代理机制");
    //执行用户调用
    userService.addUser(user);
}
1.3 静态代理弊端

1).静态代理只针对于某个接口 不能实现所有接口的代理 实用性较差

2).静态代理中所有的方法,都需要手动的添加事务开始/事务提交代码 代码冗余 不够简洁.

2.动态代理

2.1.1 动态代理分类

  1. JDK代理:
    要求: 要求目标对象必须实现接口
    代理要求: 代理对象也必须实现目标对象的接口
    目标对象/代理关系: 目标对象与代理对象兄弟关系.

  2. CGlib代理
    要求: 不管目标对象是否有接口,都可以为其创建代理对象
    代理要求: 要求代理对象必须继承目标对象
    目标对象/代理关系: 目标对象与代理对象是父子关系

在这里插入图片描述

2.2.1 编辑JDK动态代理

官网API:

在这里插入图片描述

1.关于匿名内部类用法说明: 匿名内部类引用外部参数 要求参数必须final修饰

  1. 该方法标识 当代理对象执行时,"回调"该方法.
    java public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {}
  2. 目标方法执行
    java result = method.invoke(target,args);
package com.jt.proxy;

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

//能否利用一个工厂动态为目标对象创建代理
public class JDKProxyFactory {

    //要求用户传递目标对象
    //关于匿名内部类用法说明:  匿名内部类引用外部参数 要求参数必须final修饰
    public static Object getProxy(final Object target){
        //1.调用java API实现动态代理
        /**
         *  参数分析: 3个参数
         *      1.ClassLoader loader, 类加载器(获取目标对象的Class)
         *      2.类<?>[] interfaces,  JDK代理要求 必须有接口
         *                             java中可以多实现
         *      3.InvocationHandler h  对目标方法进行扩展
         */
        //1.获取类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        //2.获取接口数组
        Class[] interfaces = target.getClass().getInterfaces();
        //3.通过动态代理创建对象
        Object proxy = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {

            //invoke方法: 代理对象调用方法时invoke执行,扩展方法的编辑位置
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // result 标识目标方法执行的返回值
                Object result = null;
                try {
                    //添加事务的控制
                    System.out.println("事务开始");
                    //执行目标方法
                    // target真实的目标对象,method方法对象,args方法参数
                    result = method.invoke(target,args);
                    System.out.println("事务提交");
                }catch (Exception e){
                    e.printStackTrace();
                    System.out.println("事务回滚");
                }
                return result;
            }
        });

        return proxy;
    }
}

2.2.2 JDK动态代理执行过程

在这里插入图片描述

2.2.3 动态代理优势

将公共的部分写到动态代理中,之后其他的业务类调用即可

2.2.4 动态代理具体案例

1).编辑DeptService/DeptServiceImpl(目标对象)

package com.jt.vo;

public interface DeptService {
    void  addDept();
}
package com.jt.vo;

import com.jt.pojo.User;
import org.springframework.stereotype.Service;

@Service("target")
public class DeptServiceImpl implements  DeptService {

    @Override
    public void addDept( ) {
        System.out.println("新增用户");
    }
}

2).编辑JDKProxyFactory(动态代理类)

package com.jt.vo;

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

//编辑JDK动态代理
public class JDKProxyFactory {
     public  static  Object getProxy(final Object target){

         //1.调用java API实现动态代理
         /**
          *  参数分析: 3个参数
          *      1.ClassLoader loader, 类加载器(获取目标对象的Class)
          *      2.类<?>[] interfaces,  JDK代理要求 必须有接口
          *                             java中可以多实现
          *      3.InvocationHandler h  对目标方法进行扩展
          */
         //1.获取类加载器
            ClassLoader classLoader = target.getClass().getClassLoader();
         //2.获取接口数组
          Class[] interfaces =   target.getClass().getInterfaces();
         //3.通过动态代理创建对象
     Object proxy   =    Proxy.newProxyInstance(classLoader,interfaces, new InvocationHandler() {
             @Override
             public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                 Object result = null;
                 try {
                     //添加事务的控制
                     System.out.println("事务开始");
                     //执行目标方法
                     // target真实的目标对象,method方法对象,args方法参数
                       result= method.invoke(target,objects);
                     System.out.println("事务结束");
                 }catch (Exception e){
                     e.printStackTrace();
                 }
                 return result;
             }
         });

         return  proxy;
     }
}

3),编辑SpringConfig配置类

package com.jt.vo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.jt.vo")
public class SpringConfig {
}

3).编辑测试类

package com.jt.vo;


import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestJDK {

    @Test
    public  void  testProxy(){

        ApplicationContext context= new AnnotationConfigApplicationContext(SpringConfig.class);
        //1.获取目标对象
         DeptService target= (DeptService) context.getBean("target");
        //2.获取代理对象
         DeptService deptService= (DeptService) JDKProxyFactory.getProxy(target);
        System.out.println(deptService.getClass());
        //3.调用业务方法
        deptService.addDept();


      }
}

4)查看测试结果

在这里插入图片描述

2.3 CCGLIB动态代理

CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,

它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供

方法的interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。

2.3.1.动态代理案例

1)实现一个业务类,注意,这个业务类并没有实现任何接口:

package com.jt.vo.cglib;

public class HelloService {

    public HelloService() {
        System.out.println("HelloService构造");
    }

    /**
     * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
     */
    final public String sayOthers(String name) {
        System.out.println("HelloService:sayOthers>>" + name);
        return null;
    }

    public void sayHello() {
        System.out.println("HelloService:sayHello");
    }

}

2)自定义MethodInterceptor:

package com.jt.vo.cglib;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 自定义MethodInterceptor
 */
class MyMethodInterceptor implements MethodInterceptor{

    /**
     * sub:cglib生成的代理对象
     * method:被代理对象方法
     * objects:方法入参
     * methodProxy: 代理方法
     */
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("======插入前置通知======");
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("======插入后者通知======");
        return object;
    }
}

3)生成CGLIB代理对象调用目标方法:

package com.jt.vo.cglib;

import org.junit.Test;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;

public class Client {

    @Test
    public  void  testCGlib(){
        // 代理类class文件存入本地磁盘方便我们反编译查看源码
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类
        enhancer.setSuperclass(HelloService.class);
        // 设置enhancer的回调对象
        enhancer.setCallback(new MyMethodInterceptor());
        // 创建代理对象
        HelloService proxy= (HelloService)enhancer.create();
        // 通过代理对象调用目标方法
        proxy.sayHello();

    }
}

4)运行结果

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值