动态代理

动态代理

代理模式的分类

  • 静态代理

  • 动态代理

    *就是可以在运行时创建一个实现了一组给定接口的新类。

    动态代理模式其实就是在 运行时动态的创建一个类实现指定的接口,并且把该实现类对象返回.

代理模式的作用

  • 拦截对真实对象的直接访问,对真实对象的功能进行增强。

动态代理开发步骤

1.先明确要代理的功能(方法)有哪些?

将要代理的功能定义在接口中
被代理类要实现接口,重写接口中的所有方法。

2.创建被代理对象(真实对象)

1)通过Proxy类的静态方法创建代理对象
  Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, Invocationhandler h)

参数ClassLoader loader:类的加载器,使用null表示使用默认的加载器。
    真实对象的类加载器对象:真实对象的类名.class.getClassLoader();

参数 Class<?>[] interfaces:需要代理的接口数组。
    即真实对象实现的接口的Class对象数组:
    1.真实对象的类名.class.getInterfaces(); 
    2.需要实现的泛型接口 可以用匿名对象new的方式传入.new Class[]{泛型接口名.class}
        
参数  Invocationhandler h:
调用处理器,使用新建的proxy对象调用方法的时候,都会调用到该接口中的invoke方法,传递一个回调处理对象(InvocationHandler接口的实现类对象h)  

注意: 
处理器 是一个接口,不能直接new对象,
所以可以自定义一个类实现处理器接口再将实现类对象传入, 
或者可以用匿名内部类的方式传入参数.
    
目标对象(需要增强的对象)都是维护在处理器内部的. 
在定义方法产生代理对象时,要将增强的代理目标对象作为参数传入. 
    
    
2)回调处理对象要重写一个invoke方法,在invoke方法里面进行指定方法的增强

该方法会拦截代理对象方法的调用,
在该方法中根据实际需求决定是否要调用真实对象的方法。

Invoke方法的参数说明
public object invoke (Object proxy , Method method , Object[]args);
proxy   代理对象
method   当前执行的方法
args        当前执行方法的实参

动态代理案例演示

案例需求

增强List集合对象的add方法,让add添加数据之前输出“开始添加数据”,执行添加数据之后输出“添加完成了”

class ListHandler implements InvocationHandler{
    //被代理的对象
    private List list;
    
    public ListHandler(List list){
        super();
        this.list = list;
    }
    /**
     * 调用指定类对象的任意方法的时候,都会调用这个方法
     *      method,当前被调用的方法
     *      args,方法需要参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //增强的add方法
        String methodName = method.getName();
        if("add".equalsIgnoreCase(methodName)){
            System.out.println("开始添加数据");
            Object object = method.invoke(list, args);//执行添加了
            System.out.println("添加完成了");
            return object;
        }else{
            //别的方法应该正常执行
            return method.invoke(list, args);
        }
    }   
}
/*
1.先明确要代理的功能(方法)有哪些?
已有List接口,不用创建

2.创建被代理对象(真实对象)

真实类ArrayList已有,不用创建
真实对象 List list = new ArrayList();

明确3参数:
类的加载器:Demo.class.getClassLoader()
代理的接口数组:new Class[]{List.class}或者ArrayList.class.getInterfaces()

InvocationHandler接口的实现类ListHandler没有,创建
InvocationHandler接口的实现类对象:new ListHandler(list)
通过Proxy类的静态方法创建代理对象
list = (List)Proxy.newProxyInstance(Demo.class.getClassLoader(), new Class[]{List.class},new ListHandler(list));
 */   
public class Demo {
    public static void main(String[] args) {
        List list = new ArrayList();
        //标准的list功能不满足我,我要代理它返回增强后的list对象
        list = (List)Proxy.newProxyInstance(Demo.class.getClassLoader(), new Class[]{List.class},new ListHandler(list));
        list.add("张三");
        list.add("李四");
        System.out.println(list);
    }
}

案例需求

  • 现有一个数据访问层类(StudentDao),类中提供了对学生进行增删改查的方法。

  • 现有一个业务层类(StudentService),该类需要调用StudentDao类中定义好的方法对学生进行增删改查操作。

  • 要求:在调用StudentDao方法之前要先判断用户是否有权限

    • 如果有权限则允许调用StudentDao方法,并在调用完StudentDao方法之后要记录日志。

    • 如果没有权限则不允许调用StudentDao方法。

    • 不允许修改StudentDao类中代码实现以上需求。

案例代码

  • 定义Dao接口

// 用来描述增删改查的功能
public interface Dao<T>{
    // 增
    public void save(T t);
    // 删
    public void delete(T t);
    // 改
    public void update(T t);
    // 查
    public T find(int id);
}
  • 数据访问层类StudentDao

/**
 * 对学生进行增删改查操作的类:数据访问层,直接跟数据库打交道
 */
public class StudentDao implements Dao<Student>{

    @Override
    public void save(Student t) {
        System.out.println("增加学生信息:" + t);
    }

    @Override
    public void delete(Student t) {
        System.out.println("删除学生信息:" + t);
    }

    @Override
    public void update(Student t) {
        System.out.println("更新学生信息:" + t);
    }

    @Override
    public Student find(int id) {
        System.out.println("查询学生信息");
        Student s =  new Student();
        System.out.println(s);
        return s;
    }
}
  • StudentService类

/*
1.先明确要代理的功能(方法)有哪些?
定义Dao接口

2.创建被代理对象(真实对象)

真实类没有, 创建数据访问层类StudentDao
真实对象 final StudentDao stuDao = new StudentDao();

明确3参数:
类的加载器:StudentService.class.getClassLoader()
代理的接口数组:StudentDao.class.getInterfaces()


InvocationHandler接口的实现类对象:
new InvocationHandler() {...}
 */ 

public class StudentService {
    public static void main(String[] args) {
        // 创建StudentDao对象(真实对象)
        final StudentDao stuDao = new StudentDao();
        
        // 创建代理对象
        Dao proxy = (Dao)Proxy.newProxyInstance(StudentService.class.getClassLoader(), 
                StudentDao.class.getInterfaces(), new InvocationHandler() {
                    /**
                     * 检查权限
                     * @return
                     */
                    public boolean check(Method m) {
                        System.out.println("检查权限");
                        if(m.getName().equals("delete")) return false;
                        return true;
                    }
                    
                    /**
                     * 记录日志
                     */
                    public void log() {
                        System.out.println("记录日志");
                    }
                    
                      //调用指定类对象的任意方法的时候,都会调用这个方法
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // System.out.println(proxy.toString());
                        // 检查是否有权限
                        if(check(method)) {
                            // 有权限,则调用真实对象的方法
                            Object result = method.invoke(stuDao, args);
                            // 记录日志
                            log();
                            return result;
                        } else {
                            // 没有权限,则不调用真实对象的方法
                            System.out.println("没权限执行操作");
                        }
                        return null;
                    }
                });
        
        proxy.save(new Student());
        proxy.update(new Student());
        proxy.delete(new Student());
        Student stu = (Student) proxy.find(1);
        System.out.println(stu);
    }
}

展开阅读全文

没有更多推荐了,返回首页