minhas informações de contato
Correspondência[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Proxy refere-se a um modo no qual um objeto A pode ter o mesmo comportamento que B mantendo outro objeto B. Para abrir o protocolo para o mundo exterior, B frequentemente implementa uma interface, e A também implementará a interface. Mas B é a classe de implementação "real", enquanto A é mais "virtual". Ela empresta os métodos de B para implementar os métodos de interface. Embora A seja um "pseudo exército", ele pode aprimorar B e fazer outras coisas antes e depois de chamar o método de B. Spring AOP usa proxies dinâmicos para completar a "tecelagem" dinâmica do código.
Os benefícios de usar um proxy vão além disso. Se um projeto depende da interface fornecida por outro projeto, mas a interface do outro projeto é instável e o protocolo é alterado com frequência, você pode usar um proxy. só precisa modificar o proxy, não um por um. Nesse sentido, podemos fazer isso para todas as interfaces que se ajustam ao mundo externo para evitar que códigos externos invadam nosso código. Isso é chamado de programação defensiva. Pode haver muitos outros aplicativos para proxy.
No exemplo acima, a classe A é codificada para conter B, que é o proxy estático de B. Se o objeto de A proxy for incerto, é um proxy dinâmico. Atualmente, existem duas implementações comuns de proxy dinâmico, proxy dinâmico jdk e proxy dinâmico cglib.
O proxy estático é um padrão de design e um tipo de padrão de proxy. Em um proxy estático, a classe de proxy foi definida antes da execução do programa e o relacionamento entre a classe de proxy e a classe de proxy é determinado em tempo de compilação. Isso significa que tanto a classe proxy quanto a classe proxy implementam a mesma interface ou herdam a mesma classe pai. A classe proxy mantém internamente uma instância da classe proxy e chama os métodos da classe proxy em seu próprio método. , ele pode adicionar algumas de suas próprias operações antes e depois da chamada, como registro em log, verificação de permissão, processamento de transações, etc.
O proxy estático possui três componentes: interface abstrata, classe proxy e classe proxy. Seus exemplos de implementação são os seguintes:
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class TargetProxy implements TargetInteface {
-
- private Target target =new Target();
- @Override
- public void method1() {
- System.out.println("执行方法前...");
- target.method1();
- System.out.println("执行方法后...");
- }
-
- @Override
- public void method2() {
- System.out.println("执行方法前...");
- target.method2();
- System.out.println("执行方法后...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("执行方法前...");
- int method3 = target.method3(i);
- System.out.println("执行方法后...");
- return method3;
- }
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println(" Target method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("Target method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("Target method3 running ...");
- return i;
- }
- }
- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = new TargetProxy();
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Saída do resultado:
Antes de executar o método...
Método de destino 1 em execução...
Depois de executar o método...
-----------------------------
Antes de executar o método...
Método de destino 2 em execução...
Depois de executar o método...
-----------------------------
Antes de executar o método...
Método de destino 3 em execução...
Depois de executar o método...
3
Não é difícil ver pela implementação de agentes estáticos que as vantagens dos agentes estáticos são a implementação simples e fácil de entender. Mas suas deficiências também são óbvias, ou seja, sempre que você precisar adicionar funcionalidade de proxy a uma nova classe, será necessário criar manualmente uma nova classe de proxy, o que levará a um aumento acentuado no número de classes e a um aumento nos custos de manutenção. . Ao mesmo tempo, o grau de acoplamento entre a classe proxy e a classe proxy é muito alto. Quando os métodos são adicionados, excluídos ou modificados na classe proxy, os métodos correspondentes também devem ser adicionados, excluídos ou modificados na classe proxy. , o que melhora o custo de manutenção do código. Outro problema é que quando o objeto proxy faz proxy das classes de implementação de múltiplas interfaces de destino, deve haver métodos diferentes nas múltiplas classes de implementação. Como o objeto proxy deve implementar a mesma interface que o objeto de destino (na verdade, um relacionamento de inclusão), ele deve. ser escrito Vários métodos podem facilmente levar a códigos inchados e difíceis de manter.
A ideia central do proxy dinâmico é acessar indiretamente o objeto original por meio do objeto proxy sem modificar o código do objeto original e realizar operações adicionais antes e depois do acesso.
O princípio de implementação do proxy dinâmico é baseado principalmente no mecanismo de reflexão Java. Ao usar proxies dinâmicos, você precisa definir uma interface ou um conjunto de interfaces que definam o comportamento da classe com proxy (objeto com proxy).Então, você precisa escrever uma implementaçãoInvocationHandler
Classe de interface, esta classe contém lógica que é executada antes e depois das chamadas de método no objeto proxy.ao ligarProxy.newProxyInstance()
método, passe o carregador de classes da interface, o array da interface eInvocationHandler
Object, Java irá gerar dinamicamente uma classe proxy que implementa a interface especificada em tempo de execução e delegar chamadas de método paraInvocationHandler
objetos a serem processados.Quando um método de um objeto proxy é chamado, ele na verdade chamaInvocationHandler
Interfaceinvoke()
Método, no qual você pode executar alguma lógica de pré-processamento com base no nome do método, parâmetros e outras informações e, em seguida, chamar o método correspondente do objeto proxy por meio de reflexão.
A seguir, apresentamos dois proxies dinâmicos: JDK Proxy e CGLib
O JDK Proxy usa o mecanismo de reflexão Java para gerar classes proxy dinamicamente. Especificamente,Proxy
classe usaráProxyGenerator
class (embora esta classe não seja uma API pública, é a chave para implementar proxy dinâmico dentro do JDK) para gerar o bytecode da classe proxy e carregá-lo na JVM.A classe proxy gerada herdará dejava.lang.reflect.Proxy
class e implementar a interface especificada.No método da classe proxy, será chamadoInvocationHandler
deinvoke
Método, encaminhe a chamada do método ao processador para processamento.
Além disso, para melhorar o desempenho, o JDK Proxy também fornece um mecanismo de cache para armazenar em cache o objeto Class da classe proxy gerada. Dessa forma, quando você precisar criar um objeto proxy do mesmo tipo, poderá obter diretamente o objeto Class da classe proxy do cache sem regenerá-lo.O cache é feito viaWeakCache
Implementado pela classe, ele usa referências fracas para objetos de cache para que os itens de cache que não são mais usados possam ser limpos automaticamente quando a JVM executa a coleta de lixo.
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
InvocationHandler
interface e reescreverinvoke
método.existirinvoke
No método, você pode adicionar lógica personalizada, como registro, verificação de permissão, etc., e chamar o método da classe original por meio de reflexão.Proxy.newProxyInstance
método, passando o carregador de classes, array de interface eInvocationHandler
Instância para gerar objetos proxy dinamicamente. Este método retorna uma instância de classe proxy que implementa a interface especificada.- public class TargetProxy {
- public static <T> Object getTarget(T t) {
- //新构建了一个 新的 代理类的对象
- return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
- //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
- System.out.println("执行方法前...");
- Object invoke = method.invoke(t, args);
- System.out.println("执行方法后...");
- return invoke;
- }
- });
- }
- }
InvocationHandler
deinvoke
Método, no qual a lógica customizada é executada e então o método da classe original é chamado.- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Saída do resultado:
Antes de executar o método...
método1 em execução...
Depois de executar o método...
-----------------------------
Antes de executar o método...
método2 em execução...
Depois de executar o método...
-----------------------------
Antes de executar o método...
método3 em execução...
Depois de executar o método...
3
MethodInterceptor
interface para definir um interceptador de método, que executará lógica customizada antes e depois da chamada de método do objeto proxy, como pré-processamento, pós-processamento, tratamento de exceções, etc.- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- public class Target {
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
MethodInterceptor
classe de interface e substituiçãointercept
método. Escreva a lógica do proxy neste método.Enhancer
classe para criar objetos proxy.Você precisa definir a classe proxy (viasetSuperclass
método) e retornos de chamada (viasetCallback
Method define a classe de implementação MethodInterceptor).- public class TargetProxy {
- public static <T> Object getProxy(T t) {
- Enhancer en = new Enhancer(); //帮我们生成代理对象
- en.setSuperclass(t.getClass());//设置要代理的目标类
- en.setCallback(new MethodInterceptor() {//代理要做什么
- @Override
- public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("执行方法前。。。");
- //调用原有方法
- Object invoke = methodProxy.invokeSuper(object, args);
- // Object invoke = method.invoke(t, args);// 作用等同与上面。
- System.out.println("执行方法后。。。");
- return invoke;
- }
- });
- return en.create();
- }
- }
intercept
Lógica proxy em métodos.- public class TargetUser {
-
- public static void main(String[] args) {
- Target target = (Target) TargetProxy.getProxy(new Target());
- System.out.println(target.getClass().getName());
- target.method1();
- }
-
- }
Saída do resultado:
com.heaboy.aopdemo.cglibproxy.TargetEeoaecerBeCGeuEUBf9f41fb8
antes de executar o método. . .
método1 em execução...
Depois de executar o método. . .
vantagem:
deficiência:
Tipo de objeto proxy:O JDK Proxy só pode fazer proxy de classes que implementam interfaces, enquanto o CGLib pode fazer proxy diretamente de classes comuns;
desempenho: CGLib gera subclasses de classes proxy em tempo de execução e geralmente é considerado um desempenho um pouco melhor que o JDK Proxy. Mas na maioria dos cenários, esta diferença de desempenho não é significativa.
cenas a serem usadas: Se o objeto de destino já implementa a interface, usar o JDK Proxy é uma escolha simples e direta. Se você precisar fazer proxy de uma classe que não implementa uma interface, deverá usar CGLib.
confiar:O JDK Proxy não requer dependências adicionais porque faz parte da biblioteca central Java, enquanto o CGLib requer a adição da biblioteca CGLib como uma dependência do projeto;
JDK Proxy é uma função que vem com a linguagem Java e não precisa ser implementada carregando classes de terceiros;
Java fornece suporte estável para JDK Proxy e continuará a atualizar e atualizar o JDK Proxy. Por exemplo, o desempenho do JDK Proxy na versão Java 8 foi bastante melhorado em comparação com as versões anteriores;
O JDK Proxy é implementado por meio de interceptadores e reflexão;
O JDK Proxy só pode fazer proxy de classes que herdam interfaces;
O JDK Proxy é relativamente simples de implementar e chamar;
CGLib é uma ferramenta fornecida por terceiros, implementada com base em ASM e com desempenho relativamente alto;
CGLib não precisa ser implementada através de uma interface, ela é chamada através da implementação de uma subclasse.
Proxy estático: Os proxies estáticos são determinados durante a compilação. Uma classe proxy precisa ser escrita para cada classe proxy. A classe proxy e a classe proxy implementam a mesma interface ou herdam a mesma classe pai.
A classe proxy de um proxy estático existe em tempo de compilação, portanto, ele só pode fazer proxy de classes específicas quando o programa está em execução e não pode decidir dinamicamente quais classes usar como proxy.
O proxy estático envolve a chamada do método do objeto original e pode adicionar lógica adicional antes e depois da chamada, mas a classe do proxy precisa ser escrita antecipadamente, o que aumentará a quantidade de código.
O proxy estático especifica explicitamente o objeto proxy no código e é relativamente intuitivo de usar, mas adicionar novas classes de proxy requer recompilação.
Proxy dinâmico: O proxy dinâmico cria objetos proxy em tempo de execução sem escrever classes de proxy antecipadamente. Use o mecanismo de reflexão do Java para gerar dinamicamente classes e objetos proxy.
Os proxies dinâmicos são baseados em interfaces e são implementados por meio da classe java.lang.reflect.Proxy e da interface java.lang.reflect.InvocationHandler.
O proxy dinâmico pode fazer proxy de classes de múltiplas interfaces e decidir dinamicamente quais classes usar como proxy. Em tempo de execução, proxies podem ser gerados para diferentes objetos conforme necessário, proporcionando maior flexibilidade.
O proxy dinâmico não precisa escrever uma classe de proxy específica para cada classe de proxy, o que é mais flexível e economiza código.
Os agentes dinâmicos podem adicionar lógica personalizada antes e depois das chamadas de método no objeto proxy, como registro, gerenciamento de transações, etc. A desvantagem do proxy dinâmico é que, comparado ao proxy estático, a geração do objeto proxy em tempo de execução requer certa sobrecarga de desempenho.
Os proxies estáticos são adequados para os seguintes cenários:
Quando o número de objetos de destino (objetos proxy) é limitado e determinado, o proxy estático pode ser implementado escrevendo manualmente classes de proxy. Os proxies estáticos criam classes de proxy em tempo de compilação, para que tenham melhor desempenho em tempo de execução.
Os proxies estáticos encapsulam o objeto de destino e adicionam funções adicionais sem modificar o código original. Isso faz com que os proxies estáticos sejam frequentemente usados para questões transversais, como registro e gerenciamento de transações.
O proxy dinâmico é adequado para os seguintes cenários:
Quando o número de objetos de destino é incerto ou não pode ser determinado antecipadamente, os proxies dinâmicos podem gerar objetos proxy de maneira mais conveniente. Ele gera classes proxy e objetos proxy em tempo de execução, evitando o trabalho tedioso de escrever manualmente várias classes proxy.
Os proxies dinâmicos fornecem flexibilidade para adicionar, remover ou alterar o comportamento do proxy para objetos de destino em tempo de execução. Isso faz com que os proxies dinâmicos sejam frequentemente usados em cenários de aplicativos como AOP (programação orientada a aspectos) e RPC (chamada de procedimento remoto).
Deve-se notar que, como os proxies dinâmicos criam classes de proxy e objetos proxy por meio do mecanismo de reflexão em tempo de execução, seu desempenho pode ser ligeiramente inferior ao dos proxies estáticos. Além disso, os proxies dinâmicos só podem fazer proxy de objetos de destino que implementam a interface, enquanto os proxies estáticos não têm essa restrição.
Resumindo, os proxies estáticos são adequados para cenários onde o número de objetos alvo é limitado e certo e requerem encapsulamento e funções adicionais, enquanto os proxies dinâmicos são adequados para cenários onde o número de objetos alvo é incerto ou não pode ser determinado antecipadamente; e o comportamento do proxy precisa ser adicionado, excluído ou alterado de maneira flexível. Escolha o método de agência apropriado com base nas necessidades e circunstâncias específicas.
Spring AOP é um módulo importante no framework Spring, usado para implementar programação orientada a aspectos.
Programação presencial , este é um modelo de programação que permite aos programadores modularizar através de pontos transversais personalizados e encapsular comportamentos que afetam múltiplas classes em módulos reutilizáveis. Exemplo: por exemplo, saída de log, se você não usar AOP, será necessário colocar as instruções de saída de log em todas as classes e métodos. No entanto, com AOP, você pode encapsular as instruções de saída de log em um módulo reutilizável e colocá-las em um módulo reutilizável. maneira declarativa. Em uma classe, a saída do log é concluída automaticamente sempre que a classe é usada.
Na ideia de programação orientada a aspectos, as funções são divididas em dois tipos
Negócio principal: Login, registro, adição, exclusão, modificação e consulta são todos chamados de negócios principais
Funções periféricas: Logs e gerenciamento de transações são serviços periféricos secundários.
Na programação orientada a aspectos, as funções essenciais de negócios e as funções periféricas são desenvolvidas de forma independente e as duas não são acopladas. Em seguida, as funções de aspectos e as funções principais de negócios são "entrelaçadas", o que é chamado de AOP.
AOP pode converter aqueles que não estão relacionados ao negócio,Mas ele é encapsulado para a lógica ou responsabilidades (como processamento de transações, gerenciamento de logs, controle de permissões, etc.) comumente chamadas por módulos de negócios.,fácil deReduza código duplicado no sistema,Reduza o acoplamento entre módulos,eConduz à escalabilidade e manutenção futuras。
Existem os seguintes conceitos em AOP:
Aspecto J: Aspect é apenas um conceito. Não existe uma interface ou classe específica correspondente. É um nome coletivo para Join point, Advice e Pointcut.
Ponto de junção : Ponto de conexão refere-se a um ponto durante a execução do programa, como invocação de método, tratamento de exceções, etc. No Spring AOP, apenas pontos de junção em nível de método são suportados.
Conselho : A notificação, ou seja, a lógica transversal num aspecto que definimos, tem três tipos: “ao redor”, “antes” e “depois”. Em muitas estruturas de implementação de AOP, o Advice geralmente atua como um interceptador e também pode conter muitos interceptadores como um link a ser processado em torno do ponto de junção.
Ponto de corte: Pointcut, usado para combinar pontos de junção Quais pontos de junção contidos em um AspectJ precisam ser filtrados por Pointcut.
Introdução : Introdução, permitindo que um aspecto declare que os objetos aconselhados implementam quaisquer interfaces adicionais que eles realmente não implementam. Por exemplo, um objeto proxy pode ser usado para fazer proxy de duas classes de destino.
Tecelagem : Tecelagem, agora que temos pontos de conexão, pontos de corte, notificações e aspectos, como aplicá-los ao programa? Isso mesmo, está tecendo. Sob a orientação de pointcuts, a lógica de notificação é inserida no método de destino, para que nossa lógica de notificação possa ser executada quando o método for chamado.
Proxy AOP : proxy AOP refere-se ao objeto que implementa o protocolo de aspecto na estrutura de implementação AOP. Existem dois tipos de proxies no Spring AOP, nomeadamente proxy dinâmico JDK e proxy dinâmico CGLIB.
Objeto alvo: o objeto de destino é o objeto que está sendo proxy.
Spring AOP é implementado com base no proxy dinâmico JDK e na promoção Cglib. Ambos os métodos proxy são métodos de tempo de execução, portanto, não possuem processamento em tempo de compilação, portanto, Spring é implementado por meio de código Java.
Alguns comportamentos comuns espalhados entre várias classes ou objetos (como registro, gerenciamento de transações, controle de permissão, limitação de corrente de interface, potência de interface, etc.), esses comportamentos são geralmente chamados preocupações transversais . Se implementarmos esses comportamentos repetidamente em cada classe ou objeto, isso levará a um código redundante, complexo e difícil de manter.
AOP pode transformar preocupações transversais (como registro, gerenciamento de transações, controle de permissão, limitação de corrente de interface, potência de interface, etc.) de Lógica central de negócios (principais preocupações, principais preocupações) Separe-se do foco para conseguir a separação de preocupações.
Registro em log: personalize anotações de registro em log e use AOP para obter registro em log com uma linha de código.
Estatísticas de desempenho: Use AOP para contar o tempo de execução do método antes e depois da execução do método alvo para facilitar a otimização e análise.
Gerenciamento de transações:@Transactional
As anotações permitem que o Spring execute o gerenciamento de transações para nós, como reverter operações de exceção, eliminando lógica de gerenciamento de transações repetidas.@Transactional
As anotações são implementadas com base em AOP.
Controle de permissão: use AOP para determinar se o usuário possui as permissões necessárias antes de executar o método de destino. Em caso afirmativo, execute o método de destino, caso contrário ele não será executado.Por exemplo, SpringSecurity utiliza@PreAuthorize
Você pode personalizar a verificação de permissão comentando uma linha de código.
Limitação de corrente de interface: Use AOP para limitar a solicitação por meio de algoritmos e implementações específicas de limitação de corrente antes que o método de destino seja executado.
Gerenciamento de cache: Use AOP para ler e atualizar o cache antes e depois da execução do método de destino.
Os métodos comuns de implementação de AOP incluem proxy dinâmico, operação de bytecode, etc.
Spring AOP é baseado em proxy dinâmico. Se o objeto a ser proxy implementar uma determinada interface, então Spring AOP usará. Proxy JDK, para criar um objeto proxy, para objetos que não implementam a interface, você não pode usar o proxy JDK para proxy. Neste momento, o Spring AOP usará. Cglib Gere uma subclasse do objeto com proxy para servir como proxy
existirspring-aop.xml
Configure beans e aspectos relacionados no arquivo de configuração
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
-
- <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
-
- <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
-
- <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="target"/> <!--被代理的类-->
- <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
- <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
- <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
- </bean>
- </beans>
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface{
-
- /*
- * 需要增强的方法,连接点JoinPoint
- **/
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
- public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
-
- /*
- * 通知/增强
- **/
- @Override
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- System.out.println("前置环绕通知");
- Object proceed = methodInvocation.proceed();
- System.out.println("后置环绕通知");
- return proceed;
- }
-
- @Override
- public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
- System.out.println("后置返回通知");
- }
-
- @Override
- public void before(Method method, Object[] args, Object target) throws Throwable {
- System.out.println("前置通知");
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
- TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
- targetProxy.method1();
- }
- }
Resultado de saída:
Notificação frontal surround
Pré-notificação
método1 em execução...
notificação pós-devolução
Notificação surround traseira
existirspring-confaop.xml
Configure beans e aspectos relacionados no arquivo de configuração
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- /*
- * 目标类
- **/
- public class Target {
-
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- /*
- * 连接点JoinPoint
- **/
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- // int i1 = 1 / i;
- return i;
- }
- }
- import org.aspectj.lang.ProceedingJoinPoint;
- /*
- * 切面类
- **/
- public class TargetAspect {
-
- /*
- * 前置通知
- **/
- public void before() {
- System.out.println("conf前置通知");
- }
-
- public void after() {
- System.out.println("conf后置通知");
- }
-
- public void afterReturning() {
- System.out.println("conf后置返回通知");
- }
-
- public void afterThrowing(Exception ex) throws Exception {
- // System.out.println("conf异常通知");
- // System.out.println(ex.getMessage());
- }
-
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("conf环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("conf环绕后置");
- }
- return proceed;
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
- Target targetProxy = (Target) appCtx.getBean("target");
- System.out.println(targetProxy.method3(0));
- }
- }
Resultado de saída:
conf pré-notificação
conf prefixo surround
método3 em execução...
conf notificação pós-devolução
postagem surround conf
conf notificação de postagem
0
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TestAnnotation{
- }
- /*
- * 切面类
- **/
- @Aspect
- @Component
- public class AnnotationAspect {
-
- // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
- @Pointcut("@annotation(TestAnnotation)")
- private void advicePointcut() {}
-
- /*
- * 前置通知
- **/
- @Before("advicePointcut()")
- public void before() {
- System.out.println("annotation前置通知");
- }
-
- @After("advicePointcut()")
- public void after() {
- System.out.println("annotation后置通知");
- }
-
- @AfterReturning(pointcut = "advicePointcut()")
- public void afterReturning() {
- System.out.println("annotation后置返回通知");
- }
-
- @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
- public void afterThrowing(Exception ex) throws Exception {
- System.out.println("annotation异常通知");
- System.out.println(ex.getMessage());
- }
-
- @Around("advicePointcut()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("annotation环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("annotation环绕后置");
- }
- return proceed;
- }
- }
- @Controller
- public class TestController {
-
- @RequestMapping("/test.do")
- @ResponseBody
- public String testController() {
- TestController o = (TestController) AopContext.currentProxy();
- o.test();
- // System.out.println("tewt");
- return "ok";
- }
-
- @TestAnnotation
- public void test() {
- System.out.println("test running");
- }
-
- }