60-线程池工厂模式动态代理

105 阅读6分钟
线程池
不要用executors创建线程,而是用threadpoolexecutor
OOM: OutOfMemoryError是因为使用了executors
public class Demo {
    public static void main(String[] args) {
        //多态的方式创建线程池对象
        /*
            参数一: 核心线程数  不能死亡的线程       corepoolsize
            参数二: 最大线程数   要求 最大线程数>=核心线程数      
                临时线程: 最大线程数 - 核心线程数    maximumpoolsize             
            参数三: 临时线程最大空闲时间keepalivetime
            参数四: 最大空闲时间的单位unit
            参数五: 任务队列workqueue
            参数六: 线程工厂    线程池中的多个线程是如何创建的threadfactory
            参数七: 拒绝策略 handler
         */
        ExecutorService pool = new ThreadPoolExecutor(3,5,60, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); 
        //证明3个核心线程忙着,再来任务进入任务队列,不会创建临时线程 
        //证明会创建两个临时线程: 核心线程正在使用,任务队列满了,临时线程可以被创建 
        //拒绝了: 核心线程正在使用,任务队列满了,临时线程使用完毕了  
    }
什么是工厂设计模式=new新建对象,它可以封装对象的创建细节,比如:为该对象进行加工和数据注入。 可以实现类与类之间的解耦操作 
对象单例模式可以保证系统中一个类只有一个对象产生  
饿汉式    为了达到目的:类一加载到内存,先加载静态成员,我们只需要new对象的时候将其变成static的就可以了
懒汉式:先不要new对象,什么时候使用,什么时候再new,但是还得保证只能是一个对象   
    问题:线程安全问题--new两次对象的情况  解决:  上锁
工厂设计--不直接new对象可以解耦最常用
//工厂 public class CarFactory {
    //静态方法: 创建抽象父类Car的子类对象的
    public static Car createCar(String msg) {
        switch (msg){
            case "bmw":
                 //多态的方式创建对象
                Car car = new BmwCar();
                car.setBrand("BMW750Li");
                car.setColor("宝强绿");
                car.setPrice(999999); 
        //通过工厂创建Car类的对象
        Car car = CarFactory.createCar("bmw");
        car.run();
                return car;
            case "audi":
                Car car2 = new AudiCar();
                car2.setBrand("奥迪A8L");
                car2.setColor("骚红");
                car2.setPrice(888888);
                Car car2 = CarFactory.createCar("audi");
        car2.run();
                return car2;
            default:
                return null;
        }
    }
}      
什么是动态代理,就是用来对业务功能(方法)进行代理的 
有了代理当访问某个方法时,会被代理对象拦截(拦截后可以对方法进行前增强、后增强【代理对象不会破坏原有方法的代码】) 
 支持任意接口类型(本身/被代理对象的所有方法)的实现类对象做代理  
 要求代理对象和被代理对象要实现相同的接口  
代理对象 = Proxy.newProxyInstance(类加载器 , 父接口 , 处理器)
Proxy类是java中定义好的专门创建代理对象的类,该类需要一个"类加载器"   
类加载器: 动态的加载.class文件
父接口 : 代理类和被代理类需要拥有共同的父接口    
处理器: 代理对象拦截了方法后,对方法进行前增强、后增强,是由处理器来书写逻辑 
代理对象  = Proxy.newProxyInstance(
             类.class.getClassLoader(), //类加载器
             被代理类.class.getInterfaces(), //父接口             
             new InvocationHandler(){代理的核心处理逻辑
                 public Object invoke(
                                       Object 代理对象, 
                                       Method 被拦截的方法对象 ,
                                       Object[] 方法中的实参
                                      ){       
                     
                     //业务逻辑
                 } 
             }
           )    
  List<String> list2 = Collections.unmodifiableList(list);//报错
使用集合工具类获取不可变List集合报错-- ,现使用动态代理模拟获取不可变List集合  
/*  unmodifiableList 获取不可改变的List集合对象,改变就会报出异常  */
public class Demo05List {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"Java","C++","Android","Python");
        System.out.println(list);
        //获取不可改变的List集合对象
        List<String> list2 = proxyList(list);
        System.out.println(list2);
        System.out.println(list2.size());
        System.out.println(list2.get(0));
        System.out.println("--------------");
        //执行以下方法均会报出异常
        //UnsupportedOperationException: 不支持的操作异常
        //list2.remove(0);
        //list2.add("Hello");
        //list2.set(0, "java");
    }
    //定义方法,获取内容不可以被改变的List集合对象
    public static List<String> proxyList(List<String> list) {
        /*
            参数一:
                ClassLoader loader: 类加载器,内部会首先创建代理类,需要加载代理类到内存
         */
        ClassLoader classLoader = list.getClass().getClassLoader();
        /*
            参数二:
                Class<?>[] interfaces: 被代理对象实现的接口,Class对象数组
                java.lang.Class类:
                    成员方法:
                        Class<?>[] getInterfaces(): 获取所有接口的Class对象数组
         */
        Class<?>[] interfaces = list.getClass().getInterfaces();
        /*
            参数三:
                InvocationHandler h: 接口,用来指定对被代理对象的方法如何进行代理的
                必须传递接口实现类对象
                    1.单独定义实现类   2.匿名内部类
         */
        InvocationHandler invocationHandler = new InvocationHandler() {
             参数一:      Object proxy: 产生的代理对象,一般此处没用
                参数二:    Method method: 反射获取的方法对象,调用的代理对象的具体的方法
                参数三:   Object[] args: 调用的代理对象的具体的方法时,传递的参数列表
                注意1:   使用代理对象调用任何方法,都会先执行invoke方法,
                    相当于具有拦截的功能,执行被代理对象的功能前可以执行其它功能,
                    在执行被代理对象的功能后可以执行其它功能
                注意2: 调用代理对象的任何方法都会执行invoke方法进行拦截
                invoke方法的返回值:   Object类型: 被代理对象的方法的返回值
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                
                //获取方法名称
                String methodName = method.getName();
                                if ("dance".equals(methodName)) {
                    //System.out.println("粉丝是找我的人跳舞.......");
                    //获取参数
                    float money = (float) args[0];
                    //超过40000,让它跳
                    if (money > 40000) {
                        return method.invoke(human,money/2);//歌星手里只能拿一半
                    }  
                }  else if ("add".equals(methodName)) {
                    //添加方法直接报异常
                    throw new UnsupportedOperationException("不支持添加操作");
                } else if ("set".equals(methodName)) {
                    //修改方法直接报异常
                    throw new UnsupportedOperationException("不支持修改操作");
                }else if ("remove".equals(methodName)) {
                    //删除方法直接报异常
                    throw new UnsupportedOperationException("不支持删除操作");
                } else {
                    //其它方法不管
                    return method.invoke(list,args);
                }
            }
        }; 
        List<String> newList = (List<String>) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
            //使用Proxy类调用静态方法,获取代理对象
        Human humanProxy = (Human) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); 
        //使用代理对象调用方法
        humanProxy.dance(50000);
        humanProxy.sing(30000);
        humanProxy.eat();
        return newList;
    }
}

使用动态代理统计系统的每个方法执行的时间

/**
   模拟用户业务功能
 */
public interface UserService {
    //登录
    String login(String loginName , String passWord) ;
    //查询所有用户
    void selectUsers();
    //删除用户
    boolean deleteUsers();
    //修改用户
    void updateUsers();
}
public class UserServiceImpl implements UserService{
    @Override
    public String login(String loginName, String passWord)  {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if("admin".equals(loginName) && "1234".equals(passWord)) {
            return "登录成功";
        }
        return "登录名和密码可能有毛病";

    }

    @Override
    public void selectUsers() {
        System.out.println("查询了100个用户数据!");
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean deleteUsers() {
        try {
            System.out.println("删除100个用户数据!");
            Thread.sleep(500);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void updateUsers() {
        try {
            System.out.println("修改100个用户数据!");
            Thread.sleep(2500);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
## 创建代理对象的工具类
 public class ProxyUtil {
    /**
      生成业务对象的代理对象。
     * @param obj
     * @return
     */
    public static <T> T  getProxy(T obj) {
        // 返回了一个代理对象了
        return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 参数一:代理对象本身。一般不管
                        // 参数二:正在被代理的方法
                        // 参数三:被代理方法,应该传入的参数
                       long startTimer = System .currentTimeMillis();
                        // 马上触发方法的真正执行。(触发真正的业务功能)
                        Object result = method.invoke(obj, args);

                        long endTimer = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法耗时:" + (endTimer - startTimer) / 1000.0 + "s");

                        // 把业务功能方法执行的结果返回给调用者
                        return result;
                    }
                });
    }
}
## 测试类
//测试类
public class Test {
    public static void main(String[] args) {
        // 1、把业务对象,直接做成一个代理对象返回,代理对象的类型也是 UserService类型
        UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
        System.out.println(userService.login("admin", "1234"));
        System.out.println(userService.deleteUsers());
        userService.selectUsers();
        userService.updateUsers(); // 走代理
    }
}