Почему в книге говорится, что JDBC наносит ущерб модели родительского делегирования? - PullRequest
0 голосов
/ 25 апреля 2018

В некоторых книгах говорится, что JDBC повреждает модель родительского делегирования, но я читал источник о том, что JDBC не найден, где показано взлом.

похоже, что каждый класс загружается Application Classloader:

public static void doingJdbc(){
    try {

        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/design", "root", "fengcs");

        String sql = "select * from tb_user";

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        preparedStatement.executeQuery();

        ResultSet resultSet = preparedStatement.getResultSet();

        while (resultSet.next()) {
            int id = resultSet.getInt(1);
            System.out.println("===================>"+ id);
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

В DriverManager также не обнаружено взлома, я не знаю, где код показывает взлом.

пожалуйста, покажи мне конкретный код, спасибо.

1 Ответ

0 голосов
/ 12 января 2019

Это нарушает модель родительского делегирования.

Модель делегирования требует, чтобы любой запрос загрузчика классов на загрузку данного класса был сначала делегирован загрузчику родительского класса, прежде чем запрашиваемый загрузчик класса попытается загрузить сам класс.

Таким образом, в соответствии с моделью делегирования java.sql.Connection в вашем фрагменте кода предполагается передать в загрузчик классов BootStrap (корневой загрузчик классов) с помощью System Classloader (он же загрузчик классов приложений), а загрузчик классов BootStrap попытается загрузить Это. И это можно загрузить.

попробовать:

    public static void main(String[] args){
        System.out.println(Connection.class.getClassLoader());
    }

Вывод равен нулю, что означает, что он загружен корневым загрузчиком классов.

Но если вы сделаете это


    public static void main(String[] args){
        Connection connection = null;
        try {
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/foo", "username", "password");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        System.out.println(connection.getClass().getClassLoader());
    }

Вывод: sun.misc.Launcher$AppClassLoader@18b4aac2 или что-то в этом роде, означающее, что он загружен Системным загрузчиком классов (Application Classloader).

Итак, мы продемонстрировали, что корневой загрузчик классов может загружать java.sql.Connection, но вместо этого загружается его дочерним классом, системным загрузчиком классов. И это является нарушением модели делегирования в соответствии с ее определением.

Тогда встает вопрос Как и Почему ?

Что касается How, уловка находится внутри класса DriverManager.

от Javadoc



 private static Connection getConnection(
        String url, java.util.Properties info, Class<?> caller) throws SQLException {

        // ...

        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;

                callerCL = Thread.currentThread().getContextClassLoader();



       // ...

        for(DriverInfo aDriver : registeredDrivers) {
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    // ...

                    Connection con = aDriver.driver.connect(url, info);

                   // ...
                        return con;
                    }

Он пытается получить загрузчик классов из текущего потока, который обычно является системным загрузчиком классов. И использовать его для загрузки реализации драйвера базы данных и возврата объекта соединения.

Или, проще говоря, родительский загрузчик классов пытается использовать дочерний загрузчик классов для загрузки некоторых классов! Согласно родительскому делегированию, родительский загрузчик классов даже не должен знать о существовании дочернего загрузчика классов.

Тогда встает вопрос: почему Sun / Oracle делает это?

Классы, загруженные двумя разными загрузчиками классов, не могут иметь доступ друг к другу. Таким образом, класс java.sql.Connection и его реализация должны быть загружены одним и тем же загрузчиком классов для работы. Тогда мы можем либо 1) Загрузите как java.sql.Connection, так и его классы реализации, предлагаемые конкретными поставщиками баз данных загрузчиком классов Bootstrap. или же 2) Загрузите оба из них загрузчиком системных классов.

Первый вариант здесь невозможен, так как мы знаем, что загрузчик классов Bootstrap загружает классы из rt.jar. Он не загружает классы из вашего пути к классам.

Второй вариант - против модели родительского делегирования, поэтому модель здесь нарушена. Это нарушение остается спорным, и некоторые люди считают это плохой дизайн.

...