静态代理与动态代理(Proxy)

        传统模式是调用放直接去调用被调用方来达到目的,这样导致的缺点是:耦合度增加。当两者增加了一个代理后,两者的耦合度会大大降低,每当调用方需要调用某个方法的时候,都回去告知代理并由代理来进行方法的调用。

一、静态代理

        在编译时就已经将接口、被代理类、代理类等确定下来,程序运行之前,代理类的.class文件就已经生成了。

        使用静态代理时,代理对象与目标对象要实现相同的接口,以此来保证两者具有相同的方法。代理对象持有目标对象的句柄。

代码实例:

接口:

public interface Subject {
    void play();
}

目标对象:

//目标对象
public class SubjectImpl implements Subject{
    @Override
    public void play() {
        System.out.println("-----目标对象----");
    }
}

代理对象:

//代理对象
public class SubjectProxy implements Subject{

    //实际的目标对象
    private Subject subject;

    public SubjectProxy(SubjectImpl subject){
        this.subject=subject;
    }

    @Override
    public void play() {
        //预处理
        System.out.println("预处理");
        subject.play();//执行目标对象的方法

        //后置处理
        System.out.println("后置处理");
    }
}

测试类:

public class StaticProxyDemo {
    public static void main(String[] args) {
        //创建实际的目标对象
        Subject subject = new SubjectImpl();

        //代理对象,把目标对象封装到代理对象中,建立代理关系
        SubjectProxy proxy = new SubjectProxy((SubjectImpl) subject);

        proxy.play();
    }
}

静态代理优点:结构简单,容易连接。能够在不修改目标对象的基础上,实现功能扩展。

静态代理缺点:当目标对象每次添加一个新的方法之后,都需要在代理对象内创建同样的方法,并对其进行包装,当方法多了的时候,代码改动相对来说会比较大且繁琐。

二、动态代理

        代理类在程序运行时创建的代理方式被称为动态代理。

        相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。

代理处理器:

1、持有目标对象的句柄

2、实现InvocationHandler接口

3、实现Invoke方法

4、所有的代理对象方法调用,都会被转发到Invoke方法来

5、Invoke的形参method,就是代理对象方法的调用

6、在Invoke内部,可以根据method,使用目标对象不同的方法来响应请求。

代码示例:

接口:

public interface Subject {
    void eat();
    void play();
}

目标对象:

//目标对象
public class SubjectImpl implements Subject{
    @Override
    public void eat() {
        System.out.println("干饭干饭!!!");
    }

    @Override
    public void play() {
        System.out.println("玩耍玩耍!!!");
    }
}

代理处理器对象:

//代理处理器对象
public class ProxyHandler implements InvocationHandler {

    //实际的目标对象
    private Subject subject;//持有真实的目标对象的句柄

    public ProxyHandler(Subject subject){
        this.subject = subject;
    }

    //当代理对象调用任何一个方法的时候,此方法都会被调用
    /**
     * proxy: 代理动态代理对象
     * method: 代表正在执行的方法
     * args: 代表调用目标方法时传入的实参
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //输出代理类的名字
        System.out.println(proxy.getClass().getName());//com.sun.proxy.$Proxy0
        System.out.println("预处理");
        Object result = method.invoke(subject, args);
        System.out.println("后置处理");

        //返回结果
        return result;
    }
}

测试类:

public class DynamicProxyDemo {
    public static void main(String[] args) {
        //创建一个实例对象,这个对象是被代理的对象
        Subject subject = new SubjectImpl();

        //创建一个与代理对象相关联的InvocationHandler
        InvocationHandler proxy = new ProxyHandler(subject);

        //创建一个代理对象stuProxy来代理subject,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
        Subject stuProxy =
                (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),new Class[]{Subject.class}, proxy);

        //代理执行吃玩的方法
        stuProxy.eat();
        stuProxy.play();
    }
}

Java动态代理的核心:

1、代理对象:不需要自己产生,由Java的Proxy这个类自动的创建出来,只要给定具体的接口,就会自己产生出这个接口的子对象。

2、代理处理器对象:需要自己定义并且实现Invoke方法。

JDK动态代理

代码示例:

业务层实现类:

@Service
public class UserServiceImpl implements UserService{
    @Override
    public void addUser() {
        try {

            System.out.println("完成用户新增!");

        }catch (Exception e){
            e.printStackTrace();
            System.out.println("事务回滚");
        }
    }

    @Override
    public void deleteUser() {
        try {

            System.out.println("完成用户删除!");

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("事务回滚");
        }
    }
}

代理类:

public class JDKProxy {
    /**
     * 获取代理对象
     * 参数说明:
     * 1.ClassLoader loader 类加载器 读取真实的类数据
     * 2.Class<?>[] interfaces   要求传递接口信息
     * 3.InvocationHandler h   当代理对象执行方法时  执行
     * 注意事项:JDK代理必须要求"被代理者"要么有接口(本身就是接口),要么实现接口(实现类)
     */

    public static Object getProxy(Object target){
        //1.获取类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        //2.获取接口
        Class[] interfaces = target.getClass().getInterfaces();
        return Proxy.newProxyInstance(classLoader,interfaces,getInvocationHandler(target));
    }

    //代理对象执行方法时调用
    private static InvocationHandler getInvocationHandler(Object target) {
        return new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("事务开始");
                //执行真实的业务方法
                Object result = method.invoke(target, args);
                System.out.println("事务提交");
                return result;
            }
        };
    }
}

配置类:

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

测试类:

public class SpringTx {
    public static void main(String[] args) {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean(UserService.class);
        System.out.println(userService.getClass());
        //获取代理对象
        UserService proxy = (UserService) JDKProxy.getProxy(userService);
        System.out.println(proxy.getClass());
        //基于代理对象,执行业务操作 实现方法扩展
        proxy.addUser();
        proxy.deleteUser();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值