【Spring】【Spring的动态代理】【静态代理思想】

代理:对类的包装,使其的方法功能更加强大.
目标对象:需要被代理的对象;
代理对象:目标对象的代理者.

静态代理

1.静态代理by接口
  • 做3件事
    1 代理对象实现于目标对象的接口
    2 将目标对象注入到代理对象中
    3 代理对象在方法中,对目标对象进行包装

代理对象的接口

public interface IUser {
    public void dowork(String name);
    public void dowork2(Integer age);
}

目标对象

public class User implements IUser{

    public void dowork(String name) {
        System.out.println("hi!"+name);
    }

    public void dowork2(Integer age) {
        System.out.println("you age "+age);
    }
}

代理对象

public class MyProxy implements IUser{
    private User user;
    public MyProxy (User user){
        this.user=User
    }
    //对方法包装
    public void dowork(String name) {
        System.out.println("开始");
        user.dowork(name);
        System.out.println("结束");
    }
    //对方法包装
    public void dowork2(Integer age) {
        Integer newAge=age+1;
        user.dowork(newAge);
    }
}

使用方式

  1. 获取目标对象
  2. 通过目标对象创建代理对象
  3. 调用代理对象的方法
    public void test1(){
        User user = new User();
        IUser Proxy=new MyProxy(user);  //用接口接收
        Proxy.dowork(XXX);
    }
2.静态代理by继承
  • 做2件事
    1 代理对象继承于目标对象的接口
    2 覆盖需要包装的方法,方法内部还是调用super.方法(),多了一些别的内容;
public class MyProxy extends User{
    //对方法包装
    public void dowork(String name) {
        System.out.println("开始");
        Super.dowork(name);   //使用目标对象的方法
        System.out.println("结束");
    }
    //对方法包装
    public void dowork2(Integer age) {
        Integer newAge=age+1;
        Super.dowork(newAge);
    }
}

使用方式

  • 直接获取代理对象进行操作即可.
    User user = new MyProxy
3.静态的缺点
  • 每一个目标对象需要一个静态代理对象.代理对象不能通用,很麻烦.
  • 解决方法:动态代理,相对静态代理,可以做出一个通用的代理对象.

Spring的动态代理

可以针对某一个功能,做出一个对不同目标对象,进行相同包装的代理类.
比如,对所有类的所有方法,都要计算出其方法运行完的时间.
静态代理需要一个类写一次代理类;动态代理写一个即可,然后代理对象通过Spring方法返回.

1.代理功能声明的类 实现于InvocationHandler

作用:可以让各种类使用从而获得代理对象
1. 创建通用的代理类,实现接口InvocationHandler,并覆盖方法invoke;
2. 创建字段,private Object obj代表目标对象,通过构造器复制;(反射方式调用方法需要传入目标对象)
3. 完成覆盖方法,实现代理.invoke(自己本身对象, 目标对象的方法,方法中的参数)

public class MyProxy implements InvocationHandler{
    //引入目标对象
    private Object obj;
    public MyProxy(Object obj) {this.obj=obj;}

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        long start = System.currentTimeMillis();
        Object ret=method.invoke(obj, args);//反射方式执行方法
        long over = System.currentTimeMillis();
        System.out.println(start-over);
        return ret;
    }
}
2.动态代理by接口

调用Spring的生成代理对象的方法
代理对象=(接口强转)Proxy.newProxyInstance(3个形参);因为返回的接口对象是实现于目标对象接口的,与目标对象是兄弟关系,要用接口接收;

  • 目标对象的类加载器 ;目标对象.getClass().getClassLoader()
  • new Class[]{接口的Class对象};//要去实现接口
  • new MyProxy(目标对象);
    @Test
    public void dowork(){
        User user=new User();
        IUser userProxy = (IUser)Proxy.newProxyInstance(user.getClass().getClassLoader()
                ,new Class[]{IUser.class}
                ,new MyProxy(user)); //返回的就是代理对象,1.必须接口接收,2.接口强转
    }
3.动态代理by继承
  • 创建一个Spring包的增强器:Enhancer en = new Enhancer();
  • 增强器器注入三个属性:
    • 目标对象的类加载器,
    • 目标对象的类对象,要去继承这个类
    • new MyProxy(目标对象);
  • 增强器生成代理对象
    @Test
    public void dowork2(){
        Enhancer en = new Enhancer();
        en.setClassLoader(user.getClass().getClassLoader());
        en.setSuperclass(user.getClass());
        en.setCallback(new MyProxy(user));
        User userProxy =(User)en.create();//返回的可以用目标对象的类接收,也可以用接口接收,强转一样

    }
4.Spring动态代理的缺点
  • 写一个InvocationHandler实现类,完成了代理功能对不同目标对象通用,
  • 但是为了获得代理对象,都需要调用生产代理对象方法,很麻烦.
  • 解决方法:Spring AOP功能,在xml中声明即可,以后目标对象对象无需额外操作,即可当代理对象使用———–Spring帮助java完成面向切面编程.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值