1. Introdução
Antes do surgimento da reflexão, quando temos uma classe java, não podemos usar a estrutura privada na classe fora da classe, por exemplo, não podemos chamar o construtor privado, o método privado, etc. Mas, após a reflexão, podemos chamar qualquer estrutura dessa classe, inclusive privada.
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionTest {
@Test
public void test1(){
Person p = new Person("tom",23);
p.show();
}
@Test
public void test2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取类对象
Class<Person> personClass = Person.class;
//2.获取类对象的构造器
Constructor constructor = personClass.getConstructor(String.class, int.class);
Object tom = constructor.newInstance("Jerry", 23);
//3.获取类方法
Method show = personClass.getDeclaredMethod("show");
show.invoke(tom);
//反射的特殊功能,可以调用私有的类结构
Constructor<Person> cons1 = personClass.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person wanglei = cons1.newInstance("wanglei");
wanglei.show();
}
}
Modo de reflexão e singleton
O padrão singleton privatiza o construtor, e espero que apenas uma instância dessa classe precise ser criada. Nesse momento, a reflexão é resolver o problema de saber se ele pode ser usado.O modo singleton é sugerir sua escrita.Eles não estão em conflito.
Compreensão de java.lang.Class
Classe como fonte de reflexão
(1) Processo de carregamento de classe: Depois que o programa é compilado por javac.exe, um ou mais arquivos de bytecode serão gerados.A classe termina, cada classe java corresponde a um arquivo de bytecode, através da interpretação java.exe para executar um certo O arquivo de bytecode do método mian. Isso é equivalente a carregar esse arquivo de bytecode na memória.Este processo é chamado de carregamento de classe. A classe gravada na memória é chamada de classe de tempo de execução, e essa classe de tempo de execução é usada como uma instância de Class. Em outras palavras, uma instância de Class corresponde a uma classe de tempo de execução.
Quatro maneiras de obter objetos de classe
//方式一:调用运行时类的属性:.class
Class clazz1 = Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象,调用getClass()
Person p1 = new Person();
Class clazz2 = p1.getClass();
System.out.println(clazz2);
//方式三:调用Class的静态方法:forName(String classPath)
Class clazz3 = Class.forName("com.atguigu.java.Person");
// clazz3 = Class.forName("java.lang.String");
System.out.println(clazz3);
System.out.println(clazz1 == clazz2);
System.out.println(clazz1 == clazz3);
//方式四:使用类的加载器:ClassLoader (了解)
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");
System.out.println(clazz4);
System.out.println(clazz1 == clazz4);
Três etapas:
Carregar: adicione o arquivo da classe à memória e crie um objeto Class. Esse processo é concluído pelo carregador de classes
Link: Verifique se as informações contidas no fluxo de bytes do arquivo de Classe atendem aos requisitos da máquina virtual atual e não colocam em risco a segurança da própria máquina virtual.
Inicialização: Ao compilar e gerar um arquivo de classe, o compilador gerará dois métodos para adicionar ao arquivo de classe, um é o clinit do método de inicialização de classe e o outro é o método de inicialização da instância init. clinit refere-se ao construtor da classe, o papel principal é desempenhar na fase de inicialização do processo de carregamento da classe, o conteúdo da execução inclui a inicialização estática de variáveis e a execução de blocos estáticos.
1. Introdução
O padrão de proxy é um dos 23 padrões de design, o que é um conhecimento mais importante.A AOP (Programação Orientada a Aspectos) mais importante na estrutura Spring também é baseada em proxy dinâmico.
Entendimento do agente
Quanto à compreensão dos agentes, deixe-me dar um exemplo: há 20 anos, a forma como queríamos comprar um computador Lenovo era: fomos à fábrica da Lenovo e a fábrica nos vendeu computadores e fornecemos serviços pós-venda.
No desenvolvimento dessas décadas, alguns revendedores apareceram. Eles compraram produtos da fábrica da Lenovo e os venderam para nós. Quando o computador quebrou, também fomos à loja do revendedor para encontrá-lo, e então ele foi à fábrica. A conexão com a fábrica estava realmente quebrada.
Em 2020, se quisermos comprar um laptop, iremos diretamente a grandes distribuidores como Tmall, Suning e JD.com para comprar um computador.Se houver algum problema, devolveremos o produto sem motivo por 7 dias.
Aqui somos o cliente Cliente, esses revendedores também são chamados de agentes e as fábricas da Lenovo são chamadas de agentes. Esse processo é um agente.
Proxy dinâmico
As características do proxy dinâmico: o código de bytes é criado e carregado a qualquer momento e carregado a qualquer momento
O papel dos agentes dinâmicos: aprimore o método sem modificar o código fonte
Classificação de agentes dinâmicos: 2 tipos, um é agente dinâmico com base na interface e o outro é agente dinâmico com base na subclasse
Proxy dinâmico baseado em interface
A implementação da classe Proxy fornecida pelo JDK requer que a classe proxy implemente pelo menos uma interface. O processo de implementação é o seguinte
(1) Primeiro crie a classe Lenovo e implemente uma interface
package com.alibaba200408.动态代理;
public class Lenovo implements ILenovo {
@Override
public void sale(Double money) {
System.out.println("拿到"+money+"元,电脑发货");
}
@Override
public void afterService(Double money) {
System.out.println("拿到"+money+"元,售后服务开始");
}
}
O código é muito simples, apenas dois métodos estão envolvidos, um é vender o computador e o outro é reparar o computador.
O código da interface é o seguinte
package com.alibaba200408.动态代理;
public interface ILenovo {
void sale(Double money);
void afterService(Double money);
}
(2) Instanciar um objeto proxy dinâmico e chamar métodos por meio do objeto proxy
package com.alibaba200408.动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
//联想厂家
ILenovo lenovo = new Lenovo();
//创建代理对象
ILenovo proxyInstance = (ILenovo) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(),
lenovo.getClass().getInterfaces(),
new InvocationHandler() {
/**
* invoke方法的作用是调用任何被代理对象的方法都会被这个invoke方法拦截
* proxy:表示当前代理对象的引用
* method:表示当前正在执行的方法
* args:表示当前执行的方法的参数
*
* 返回值就是当前方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//提供增强的代码
Double money = (Double) args[0];
if ("sale".equals(method.getName())){
method.invoke(lenovo, money * 0.8);
}else {
method.invoke(lenovo,args);
}
return null;
}
});
proxyInstance.afterService(10000.0);
}
}
Agente dinâmico baseado na subclasse
Essa implementação requer que a classe proxy não possa ser final, porque a classe final modificada não pode ter subclasses e, em segundo lugar, esse método requer um cglib de terceiros. Não vou repeti-los aqui.