Entrevistador: ¿Qué es un proxy estático? ¿Qué es un proxy dinámico? ¿Conoces la anotación y la reflexión?

prefacio

apertura

Un hombre de mediana edad que viste una camisa azul, jeans y sostiene un termo blanco está sentado frente a usted con prisa. Parece que el proyecto tiene prisa. Se estima que el tiempo de la entrevista no será demasiado largo, por lo que Me siento relajado Muchos... (Me dieron una bofetada en la cara después)

Comienza la entrevista

Entrevistador: Joven, veo que su currículum dice que domina los conceptos básicos de Java, correcto, así que primero le preguntaré brevemente algunos conceptos básicos de Java.

Está bien, pregúntale al entrevistador. (Tan pronto como escuché las dos simples palabras, estaba secretamente encantado...)

Entrevistador: ¿Sabías que hay una cosa en Java llamada proxy?

Ya sabes, el agente debe acceder al objeto de destino real a través del objeto del agente. Por ejemplo, cuando alquilamos una casa en nuestra vida, podemos encontrar directamente al propietario, o podemos alquilar una casa a través de algunas plataformas de alquiler. Esta forma de el uso de la plataforma de alquiler es un agente. En java, este tipo de plataforma de alquiler se llama clase de proxy.La clase de proxy no solo puede realizar el objeto de destino, sino también agregar algunas funciones adicionales. Hasta donde yo sé, hay proxy estático y proxy dinámico en el modo proxy en java. (En este momento, lo más probable es que el entrevistador le pregunte acerca de estos dos modos de agencia).

Entrevistador: No esperaba que entendieras el código a través de los fenómenos de tu vida. No está mal. Veo que mencionaste el proxy estático y el proxy dinámico. Entonces dime qué es el proxy estático.

(Efectivamente, pregunté, pero afortunadamente hice los preparativos) Proxy estático significa que esta clase de proxy ya existe antes de que se ejecute el código. Tomando el alquiler anterior como ejemplo, primero se creará una interfaz de alquiler general en el código:

public interface Room {
    
    
    void rent();
}1.2.3.

Luego, debe tener una clase de proxy (o clase real) y una clase de proxy:

public class RealRoom implements Room {
    
    
    private String roomname;
    public RealRoom(String roomname) {
    
    
        this.roomname = roomname;
    }
    public void rent() {
    
    
        System.out.println("租了"+roomname);
    }
}1.2.3.4.5.6.7.8.9.

La clase de proxy es la siguiente:

public class ProxyClass implements Room {
    
    
    RealRoom realRoom;
    public ProxyClass(RealRoom realRoom) {
    
    
        this.realRoom = realRoom;
    }
    public void rent() {
    
    
        System.out.println("租房前收取中介费");
        realRoom.rent();
        System.out.println("租房后收取服务费");
    }
}1.2.3.4.5.6.7.8.9.10.11.

La clase proxy puede agregar funcionalidad sin cambiar el objeto proxy.Finalmente, probemos este proxy estático:

public class Main {
    
    
    public static void main(String[] args) {
    
    
        RealRoom realRoom =new RealRoom("碧桂园");
        ProxyClass proxyClass=new ProxyClass(realRoom);
        proxyClass.rent();
    }
}1.2.3.4.5.6.7.

Luego observa el resultado:

租房前收取中介费
租了碧桂园
租房后收取服务费1.2.3.

Entrevistador: Dado que el proxy estático es tan poderoso, ¿tiene alguna desventaja?

Dado que ya existe una clase de proxy para un proxy estático antes de que se ejecute el código, se debe crear una clase de proxy para cada objeto de proxy al proxy. Cuando hay muchos objetos que deben ser proxy, se deben crear muchas clases de proxy, lo que en serio reduce la mantenibilidad del programa. Este problema se puede resolver con un proxy dinámico.

Entrevistador: Entonces háblame de los agentes dinámicos.

Proxy dinámico significa que la clase de proxy no está escrita en el código, sino que se genera durante el proceso de ejecución.Java ofrece dos formas de implementar un proxy dinámico, que son el proxy dinámico basado en Jdk y el proxy dinámico basado en Cglib.

Entrevistador: Olvidé el proxy dinámico basado en JDK, me das una revisión.

(Lo olvidé) Para implementar el proxy dinámico de Jdk, debe implementar la interfaz InvocationHandler y luego implementar el método de invocación. Si se llama al método del proxy, el proxy lo notificará y lo reenviará a la invocación de la clase de implementación interna InvocationHandler, que implementa el contenido de procesamiento.

public class ProxyHandler implements InvocationHandler {
    
    
    Object object;
    public ProxyHandler(Object object) {
    
    
        this.object = object;
    }
    //proxy 代理对象
    //method 要实现的方法
    //args 方法的参数    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        System.out.println("代理执行之前:"+method.getName());
        Object invoke = method.invoke(object, args);
        System.out.println("代理执行之后:"+method.getName());
        return invoke;
    }
}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.

A continuación, ejecute el proxy dinámico en el método principal

public static void main(String[] args) {
    
    
    Room room=new RealRoom("碧桂园");
    //obj.getClass().getClassLoader()类加载器
    //obj.getClass().getInterfaces() 目标类实现的接口
    //InvocationHandler对象
    InvocationHandler invocationHandler=new ProxyHandler(room);
    Room proxyRoom = (Room) Proxy.newProxyInstance(room.getClass().getClassLoader(), room.getClass().getInterfaces(), invocationHandler);
    proxyRoom.rent();
}1.2.3.4.5.6.7.8.9.

El núcleo de este código es Proxy.newProxyInstance, el propósito es generar una clase de proxy durante el tiempo de ejecución y finalmente ejecutar el método de proxy a través de la clase de proxy. El resultado final es el siguiente:

代理执行之前:rent
租了碧桂园
代理执行之后:rent1.2.3.

Entrevistador: Después de decir eso, pienso en el agente dinámico, ¿qué hay de sus ventajas?

Cuando hablé antes de los proxies estáticos, dije que la desventaja de los proxies estáticos es que para cada objeto de proxy, se necesita construir una clase de proxy. Porque el proxy estático se escribe antes de que se ejecute el proyecto. Pero este no es el caso con los proxies dinámicos, dado que los proxies dinámicos solo crean clases de proxy en tiempo de ejecución, solo necesita escribir una clase de proxy dinámico. Por ejemplo, creo un objeto proxy para vender una casa:

Escribir una interfaz genérica Vender

public interface Sell {
    
    
    void sellRoom();
}1.2.3.

Luego escribe una clase para el objeto proxy:

public class RealSell implements Sell {
    
    
    public void sellRoom() {
    
    
        System.out.println("卖房了");
    }
}1.2.3.4.5.

A continuación, ejecute el proxy dinámico en el método principal

    public static void main(String[] args) {
    
    
        Sell sell=new RealSell();
        InvocationHandler invocationHandler=new ProxyHandler(sell);
        Sell proxysell= (Sell) Proxy.newProxyInstance(sell.getClass().getClassLoader(),sell.getClass().getInterfaces(),invocationHandler);
        proxysell.sellRoom();
    }1.2.3.4.5.6.

El resultado final es el siguiente:

代理执行之前:sellRoom
卖房了
代理执行之后:sellRoom1.2.3.

A través del proxy dinámico, puedo representar múltiples objetos a través de una clase de proxy dinámico.

Entrevistador: Si no recuerdo mal, solo puede usar interfaces proxy de esta manera. Veo que sus ejemplos anteriores son todas interfaces proxy, entonces, ¿qué debo hacer si quiero usar clases proxy?

El proxy dinámico jdk solo puede representar la interfaz. El proxy dinámico JDK se basa en la interfaz. En otras palabras, tanto la clase de proxy como la clase de destino implementan la misma interfaz. Si desea una clase de proxy, puede usar CGLib. El proxy dinámico de CGLib es una clase de proxy para heredar la clase de destino y luego implementar el método de la clase de destino.

Crear una clase de destino CGRoom

public class CGRoom {
    
    
    public void rent(String roomName){
    
    
        System.out.println("租了"+roomName);
    }
}1.2.3.4.5.

Cree una clase de proxy dinámica de cglib, herede MethodInterceptor e implemente el método de intercepción en ella

public class MyMethodInterceptor implements MethodInterceptor {
    
    

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
        System.out.println("代理执行之前:"+method.getName());
        Object object=methodProxy.invokeSuper(o,objects);
        System.out.println("代理执行之后:"+method.getName());
        return object;
    }
}1.2.3.4.5.6.7.8.9.

Finalmente, cree una clase de proxy a través del objeto de mejora.

public static void main(String[] args) {
    
    
    //创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
    Enhancer enhancer=new Enhancer();
    //设置目标类的字节码文件
    enhancer.setSuperclass(CGRoom.class);
    //设置回调函数
    enhancer.setCallback(new MyMethodInterceptor());
    //创建代理对象
    CGRoom proxy= (CGRoom) enhancer.create();
    proxy.rent("碧桂园");
}1.2.3.4.5.6.7.8.9.10.11.

Finalmente lograr los siguientes resultados:

代理执行之前:rent
租了碧桂园
代理执行之后:rent1.2.3.

Entrevistador: Ya que el proxy dinámico es tan bueno como dices, ¿lo usas en tu trabajo diario?

Por lo general, aunque los proxies dinámicos apenas se usan en mi código comercial, los proxies dinámicos se usan en AOP en los marcos de trabajo de la serie Spring que uso en mi trabajo, así como en los marcos RPC Tomando AOP como ejemplo, AOP realiza proxies dinámicos en el Objeto de destino Mejoras, como nuestras notificaciones previas y posteriores más utilizadas, etc.

Entrevistador: ¡Bien! A continuación, probaré algunos conceptos básicos, hablaré sobre su comprensión de las anotaciones y qué problemas resuelven las anotaciones.

Clases, métodos, variables, parámetros y paquetes en el lenguaje Java se pueden marcar con anotaciones, durante la ejecución del programa podemos obtener las anotaciones correspondientes y el contenido definido en las anotaciones, por ejemplo si Spring detecta que tu clase es @@ Si la anotación Componente está marcada, el contenedor Spring clasificará esta clase como su propia administración cuando se inicie, para que pueda inyectar este objeto a través de la anotación @Autowired.

Entrevistador: ¿Sabe cómo definir las anotaciones usted mismo?

Ya sabes, las anotaciones personalizadas tienen principalmente los siguientes cuatro pasos:

El primer paso es declarar la anotación a través de @interface:

public @interface Myannotation {
    
    
    String key() default "";
}1.2.3.

El segundo paso es modificar las anotaciones a través de cuatro tipos de meta-anotaciones: (Puede decir estos cuatro tipos de anotaciones durante la entrevista)

El papel de la meta-anotación es ser responsable de otras anotaciones. Hay cuatro meta-anotaciones en java, a saber, @Target, @Retention, @Documented, @Inherited. Primero, presentemos las funciones de las siguientes cuatro anotaciones:

@Target: Target indica el alcance del objeto modificado por la anotación.Los valores (ElementType) son:

  1. Se usa para describir constructores.
  2. se usa para describir propiedades
  3. Se utiliza para describir variables locales.
  4. utilizado para describir el método
  5. usado para describir el paquete
  6. se utiliza para describir parámetros
  7. Se utiliza para describir clases, interfaces (incluidos los tipos de anotaciones) o declaraciones de enumeración

@Retention: Retention define el rango de retención de las anotaciones, y los valores (RetentionPoicy) son:

  1. Válido en los archivos de origen (es decir, los archivos de origen permanecen)
  2. Válido en archivos de clase (es decir, retención de clase)
  3. Válido en tiempo de ejecución (es decir, tiempo de ejecución preservado)

@Documentado: Documentado se usa para describir la API pública que otros tipos de anotaciones deben usarse como miembros del programa anotados y, por lo tanto, pueden documentarse con herramientas como javadoc. Documentado es una anotación de marcado sin miembros.

@Inherited: la metaanotación Inherited es una anotación de marcado, @Inherited indica que se hereda un tipo anotado. Si se usa un tipo de anotación @Inherited en una clase, la anotación se usará en las subclases de esa clase.

@Target({
    
    ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Myannotation {
    
    
    String key() default "";
}1.2.3.4.5.6.7.

El tercer paso usa anotaciones, porque MEHTOD y FIELD se definen cuando se define Target, por lo que esta anotación se puede usar en propiedades y métodos:

public class MyannotationTest {
    
    
    @Myannotation(key = "javayz")
    private String username;
}1.2.3.4.

El cuarto paso utiliza la reflexión para analizar las anotaciones.

public static void main(String[] args) {
    
    
    Class myclass=MyannotationTest.class;
    Field[] fields = myclass.getDeclaredFields();
    for (Field field :fields){
    
    
        if (field.isAnnotationPresent(Myannotation.class)){
    
    
            System.out.println("配置了自定义注解");
            Myannotation annotation = field.getAnnotation(Myannotation.class);
            System.out.println("属性:"+field.getName()+"上的注解key为"+annotation.key());
        }
    }
}1.2.3.4.5.6.7.8.9.10.11.

Resultado de salida:

配置了自定义注解
属性:username上的注解key为javayz1.2.

Entrevistador: Veo que mencionó la reflexión en el paso 4 anterior, ¿verdad? Entonces dime qué es la reflexión y cuáles son sus características:

(Estoy mareado, solo dije la palabra reflexión, afortunadamente para estar preparado) El mecanismo de reflexión JAVA está en estado de ejecución, para cualquier clase, puede conocer todas las propiedades y métodos de esta clase; para cualquier objeto, todo puede llamar a cualquiera de sus métodos y propiedades; esta adquisición dinámica de información y la capacidad de llamar dinámicamente a los métodos del objeto se denomina mecanismo de reflexión del lenguaje java.

En el cuarto paso anterior usando la reflexión para analizar las anotaciones, obtuve el objeto de clase de MyannotationTest a través de MyannotationTest.class y obtuve todas las propiedades con myclass.getDeclaredFields();. Esto es reflexión.

final

Entrevistador: Sí, has superado los conceptos básicos de estas piezas. ¡Ahora comenzaré la verdadera entrevista técnica!

Supongo que te gusta

Origin blog.csdn.net/m0_48795607/article/details/120212215
Recomendado
Clasificación