java方法增强的三种方式:继承,装饰和代理

在java中,在不改变源代码的情况下,实现方法增强的方式有三种:

  • 1,继承
  • 2,装饰者模式
  • 3,代理模式(静态代理和动态代理)
1,继承模式:
  • 简单来说,就是通过继承的方式,在子类方法中添加相应的增强方法,然后通过调用子类方法来实现增强。
//继承比较简单,直接继承,重写中调用父类方法即可
2,装饰者模式:
  • 装饰者模式是真正完全不改变源码的情况下增强方法的一种方式,即便是调用方式也无需改变
  • 这里用自定义的连接池来进行说明
  • 在自定义连接池中,如果没有增强过Connection的话,那么是不能按照原来的方式直接调用connection.close();方法的,那么可以通过装饰,把连接池中的Connection对象直接在放入池之前包装成我自定义的Connection,这样从连接池中取出来的连接也是我自定义的连接,那么只需要在自定义的方法中实现close()和prepareStatement等就可以达到直接调用关闭方法的目的,具体如下:
//1,自定义连接池
/*
 * 对JDBC连接的封装,也就是自定义连接池
 * 其他一些方法也需要重写,但是不需要任何改变,所以这里就没有贴出来
 */
public class JDBCDatasource implements DataSource {
    private static LinkedList<Connection> connections = new LinkedList<Connection>();
    //往连接池中添加连接
    static{
        for(int i=0;i<5;i++){
            Connection connection = JDBCUtil.getConnection();
            JDBCConnection theConnection = new JDBCConnection(connections, connection);
            connections.add(theConnection);
        }
    }
    //重写这一个方法,如果没有增强过connection的话,需要调用这个方法归还连接到连接池中
    @Override
    public Connection getConnection() throws SQLException {
        if (connections.size() == 0) {
            for(int i=0;i<5;i++){
                Connection connection = JDBCUtil.getConnection();
                JDBCConnection theConnection = new JDBCConnection(connections, connection);
                connections.add(theConnection);
            }
        }
        return connections.removeFirst();
    }
     //新增一个方法
    public void returnConnection(Connection connection){
        connections.add(connection);
    }
}

//2,自定义连接类,实现相应的方法,并在自定义的连接池中进行包装,具体看1中的代码
//其他一些不需要修改的覆盖方法这里不再贴出
public class JDBCConnection implements Connection {
    private Connection connection;
    private LinkedList<Connection> connections;
    public JDBCConnection(List<Connection> connections, Connection connection) {
        this.connections = (LinkedList<Connection>) connections;
        this.connection = connection;
    }
    //如果想要在关闭的时候添加到连接池,那么需要把连接池传进来,传进来最好的时候就是创建的时候
    @Override
    public void close() throws SQLException {
        System.out.println("here here!");
        connections.add(connection);
    }
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }
}

//测试
JDBCDatasource datasource = new JDBCDatasource();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
    connection = datasource.getConnection();
    preparedStatement = connection.prepareStatement("select * from product;");
    resultSet = preparedStatement.executeQuery();
    while(resultSet.next()){
        System.out.println(resultSet.getString("pname"));
    }
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    //这行代码中封装了connection.close()方法
    JDBCUtil.closeAll(connection, preparedStatement, resultSet);
}

3,代理模式:
  • 代理分为动态代理和静态代理,区别就是静态代理是自己创建一个代理类,实现相应的被代理对象的方法,增加相应的增强代码。而动态代理是通过类加载器,反射等在运行时创建代理类,也就是不需要手动创建代理类,在对应的代理方法newProxyInstance中的代码块中直接添加增强代码;
  • 动态代理是在静态代理的基础上的拓展,所以先看下静态代理:
//1,首先需要有一个接口类,方便目标对象和代理对象去实现
public interface DogInterface {
    public void eat();
    public void run();
}

//2,目标对象中实现借口类
public class Dog implements DogInterface {
    @Override
    public void eat() {
        System.out.println("Dog  -----eat");
    }
    @Override
    public void run() {
        System.out.println("dog----run----");
    }
}

//3,创建一个代理对象,在代理对象中实现借口类,并在对应的方法中调用目标对象的方法。
public class DogProxy implements DogInterface {
    @Override
    public void eat() {
        System.out.println("dog在eat前,准备工作代码等");
                //这里调用目标对象的方法
        Dog dog = new Dog();
        dog.eat();
        System.out.println("dog在eat后收尾工作代码等");
    }
    @Override
    public void run() {
    }
}

//4,实际使用时候使用代理对象即可
public void proxyTest(){
    DogProxy proxy = new DogProxy();
    proxy.eat();//这里就ok了
}
  • 下面是动态代理的代码实现,前两步是完全一致的
    有一点需要注意的是:动态代理方法虽然能增强方法,但主要的使用场合是在拦截中进行相应的处理,如在全局的拦截器中进行乱码处理等
//1,首先需要有一个接口类,方便目标对象和代理对象去实现
public interface DogInterface {
    public void eat();
    public void run();
}

//2,目标对象中实现借口类
public class Dog implements DogInterface {
    @Override
    public void eat() {
        System.out.println("Dog  -----eat");
    }
    @Override
    public void run() {
        System.out.println("dog----run----");
    }
}

//3,在调用的时候使用代理类调用静态方法创建动态代理
 public void dynamicProxyTest(){
    DogInterface proxy = (DogInterface) Proxy.newProxyInstance(
            Dog.class.getClassLoader(), 
            Dog.class.getInterfaces(), //new Class[]{DogInterface.class}
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("before");
                    method.invoke(new Dog(), args);
                    System.out.println("after");
                return null;
        }
    });
    proxy.eat();
    proxy.run();
}
//搞定!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容