← Назад к вопросам

Создает ли Proxy новый объект того же типа, что и исходный проксируемый объект

2.0 Middle🔥 111 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответ

Это отличный вопрос, который показывает понимание паттернов проектирования. Ответ - НЕТ, Proxy НЕ создаёт новый объект того же типа. Вместо этого создаётся новый объект другого типа, который реализует тот же интерфейс или наследует тот же базовый класс.

Что такое Proxy

Proxy (прокси) - это паттерн проектирования, который позволяет добавить дополнительное поведение к объекту без изменения его кода. Proxy действует как посредник между клиентом и реальным объектом.

Два типа Proxy в Java

1. Статический Proxy (ручной) Мы создаём класс, который реализует тот же интерфейс:

// Исходный интерфейс
public interface UserService {
    User getUser(Long id);
    void saveUser(User user);
}

// Реальная реализация
public class UserServiceImpl implements UserService {
    @Override
    public User getUser(Long id) {
        // Работа с БД
        return new User(id);
    }
    
    @Override
    public void saveUser(User user) {
        // Сохранение в БД
    }
}

// Proxy
public class UserServiceProxy implements UserService {
    private UserService realService;
    
    public UserServiceProxy(UserService realService) {
        this.realService = realService;
    }
    
    @Override
    public User getUser(Long id) {
        System.out.println("Логирование: получение пользователя " + id);
        return realService.getUser(id); // Делегируем реальному объекту
    }
    
    @Override
    public void saveUser(User user) {
        System.out.println("Логирование: сохранение пользователя");
        realService.saveUser(user);
    }
}

// Использование
UserService realService = new UserServiceImpl();
UserService proxy = new UserServiceProxy(realService);

proxy.getUser(1L); // Логирование + вызов реального сервиса

// proxy НЕ является объектом того же типа что UserServiceImpl
System.out.println(proxy instanceof UserServiceImpl); // false
System.out.println(proxy instanceof UserService); // true

2. Динамический Proxy (отражение) Java может создать Proxy в runtime используя Reflection API:

UserService realService = new UserServiceImpl();

UserService proxy = (UserService) Proxy.newProxyInstance(
    UserService.class.getClassLoader(),
    new Class[]{UserService.class},
    new InvocationHandler() {
        @Override
        public Object invoke(Object proxyObj, Method method, Object[] args) 
            throws Throwable {
            System.out.println("Логирование: вызов метода " + method.getName());
            return method.invoke(realService, args); // Делегируем реальному объекту
        }
    }
);

proxy.getUser(1L); // Логирование + вызов реального сервиса

// proxy НЕ UserServiceImpl, это созданный Proxy класс
System.out.println(proxy.getClass().getName()); // com.sun.proxy.$Proxy0
System.out.println(proxy instanceof UserServiceImpl); // false
System.out.println(proxy instanceof UserService); // true

Ключевые отличия

// Исходный объект
UserService real = new UserServiceImpl();
System.out.println(real.getClass().getName()); // UserServiceImpl

// Статический Proxy
UserService staticProxy = new UserServiceProxy(real);
System.out.println(staticProxy.getClass().getName()); // UserServiceProxy

// Динамический Proxy
UserService dynamicProxy = (UserService) Proxy.newProxyInstance(...);
System.out.println(dynamicProxy.getClass().getName()); // $Proxy0

// Все реализуют интерфейс UserService
System.out.println(real instanceof UserService); // true
System.out.println(staticProxy instanceof UserService); // true
System.out.println(dynamicProxy instanceof UserService); // true

// Но их типы РАЗНЫЕ
System.out.println(real.getClass() == staticProxy.getClass()); // false
System.out.println(real.getClass() == dynamicProxy.getClass()); // false

Реальные примеры в Java экосистеме

Spring AOP (Aspect Oriented Programming) Spring использует Proxy для реализации @Transactional, @Cacheable и других аннотаций:

@Service
public class UserService {
    @Transactional
    public void saveUser(User user) {
        // Реальный код
    }
}

// Spring создаёт Proxy:
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(userService.getClass().getName()); 
// org.springframework.cglib.proxy.UserService$$EnhancerBySpringCGLIB$$...

Hibernate Lazy Loading Cglib используется для создания Proxy объектов с lazy loading:

@Entity
public class User {
    @OneToMany(fetch = FetchType.LAZY)
    private List<Order> orders;
}

User user = session.get(User.class, 1L);
System.out.println(user.getClass().getName()); 
// User_$$_jvst_... (Javassist Proxy)

CGLib vs JDK Dynamic Proxy

JDK Dynamic Proxy:

  • Работает только с интерфейсами
  • Используется в Spring для интерфейсов
  • Встроено в Java

CGLib:

  • Может работать с классами (не только интерфейсами)
  • Используется Spring для классов без интерфейсов
  • Требует внешнюю библиотеку
// JDK Proxy - нужен интерфейс
public interface UserService { }
public class UserServiceImpl implements UserService { }
// OK - JDK Proxy

// CGLib - может работать без интерфейса
public class UserService { }
// CGLib создаст подкласс UserService

Best Practices

  1. Proxy НЕ меняет тип объекта - создаёт новый объект, реализующий тот же интерфейс
  2. Используй интерфейсы - это делает Proxy прозрачным для клиента
  3. Помни о производительности - Proxy добавляет overhead
  4. Используй Spring AOP - вместо ручного создания Proxy
  5. Профилируй - убедись, что Proxy не создаёт узких мест

Это понимание критично для работы с современными фреймворками, которые используют Proxy под капотом для реализации key features.

Создает ли Proxy новый объект того же типа, что и исходный проксируемый объект | PrepBro