As notificações da Spring AOP são divididas em cinco categorias:
Antes do conselho: execute em frente ao ponto de conexão. A visualização não afetará a execução do ponto de conexão, a menos que uma exceção seja lançada aqui.
Notificação normal de retorno [após o retorno do conselho]: Execute após a execução normal do ponto de conexão. Se uma exceção for lançada pelo ponto de conexão, ela não será executada.
Notificação de retorno da exceção [Após o atendimento, execute após uma exceção for lançada pelo ponto de conexão.
Notificação de retorno [após (finalmente) aconselhamento]: Após a execução ser concluída, o conteúdo da notificação de retorno será executado se ela é concluída normalmente ou uma exceção será lançada.
Conselhos: conselhos sobre o ponto de conexão, como antes e depois de uma chamada de método. Este é o tipo de notificação mais poderoso, que pode personalizar algumas operações antes e depois das chamadas do método.
A notificação circundante também precisa decidir se continua processando o ponto de junção (chamando o método do processo do ProssingJoinPoint) ou interromper a execução.
Em seguida, testaremos cinco tipos de notificação escrevendo um programa de amostra:
Defina interface
pacote com.chenqa.springaop.example.service; interface pública BankService { / *** transferência bancária simulada* @param da conta* @param para conta* @param Conta de transferência Valor* @return* / public boolean transfer (string formulário, string para, conta dupla);}Escreva classes de implementação
pacote com.chenqa.springaop.example.service.impl; importar com.chenqa.springaop.example.service.bankservice; classe pública BcMBankServiceImpl implementa o BankService {public boolean transfer (string, string to duplo) yuan "); } System.out.println (formulário+"transferência para"+para+"conta bancária"+conta+"yuan"); retornar falso; }}Modifique o arquivo de configuração da mola e adicione o seguinte:
<!-BankService Bean-> <bean id = "BankService"/> <!-Seção-> <bean id = "myaspect"/> <!-AP Configuration-> <Aop: config> <aOp: Aspect Ref = "MyAspect"> <AOP: Pointcut Expression = "Execution (*com.chenqa.s.sning.sning.sning.sning.sning.sning.sning.sning.sning.sning.sning.sning.sning.SPRESE (*MyAsPree". id="pointcut"/> <aop:before method="before" pointcut-ref="pointcut"/> <aop:after method="after" pointcut-ref="pointcut"/> <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/> <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/> <aOP: em torno do método = "em torno" Pointcut-ref = "Pointcut"/> </aOP: Aspect> </aOP: config>
Escrevendo um programa de teste
ApplicationContext context = new ClassPathXMLApplicationContext ("spring-aop.xml"); BankService BankService = Context.getBean ("BankService", BankService.class); BankService.Transfer ("Zhang San", "Li Si", 200); Saída após execução:
Altere 200 no programa de teste para 50 e depois a saída após a execução:
A partir dos resultados do teste, pode -se observar que a ordem de execução das cinco notificações é:
Notificação pré-notificação → Notificação surround → Notificação de retorno normal/Notificação de retorno de exceção → Notificação de retorno, você pode executar várias vezes para visualizar.
Caso 1: Um método é interceptado apenas por uma classe de aspecto
Quando um método é interceptado por apenas um aspecto, em que ordem os diferentes conselhos nesse aspecto são executados? Por favor, veja:
Adicione a classe Pointcut
Este Pointcut é usado para interceptar todos os métodos em todas as classes no pacote de teste.
teste do pacote; importar org.aspectj.lang.annotation.pointcut; public class Pointcuts {@PointCut (value = "dentro (test.*)") public void AopDemo () {}}}Adicione a classe de aspecto
Os conselhos desta classe usarão o ponto acima. Consulte o atributo de valor de cada conselho ao usá -lo.
teste de pacote; importar org.aspectj.lang.joinpoint; importar org.aspectj.lang.proecedingJoinPoint; importar org.aspectj.lang.annotation.*; importar org.springframework.tereotype.component;@component@aspecto da classe ASPECT1 {@BeFore (valueReotyPy.comPons.Conen; {System.out.println ("[aspecto1] antes do conselho"); } @Around (value = "test.pointcuts.aopdemo ()") public void em torno (ProceedingJoinPoint PJP) lança arremesso {System.out.println ("[aspecto1] em torno do conselho 1"); pjp.proeced (); System.out.println ("[aspecto1] em torno do conselho2"); } @AfterReturning (value = "test.pointcuts.aopdemo ()") public void após retornar (junção junção) {System.out.println ("[aspecto1] após o conselhos após o retorno"); } @AfterWROWLE (value = "test.pointcuts.aopdemo ()") public void AfterWring (junção junção) {System.out.println ("[aspecto1] conselhos posteriores"); } @After (value = "test.pointcuts.aopdemo ()") public void após (junção junção) {system.out.println ("[aspecto1] conselhos posteriores"); } @After (value = "test.pointcuts.aopdemo ()") public void após (junção junção) {system.out.println ("[aspecto1] após o conselho"); }}Adicione um controlador de teste
Adicione um controlador para teste. Existe apenas um método nesse controlador, mas ele lidará de maneira diferente de acordo com os valores dos parâmetros: um é retornar um objeto normalmente e o outro é lançar uma exceção (porque queremos testar os conselhos @afterwrowing)
teste de pacote; importar test.exception.testException; importar org.springframework.http.httpstatus; importar org.springframework.web.bind.annotation.*;@reestcontroller@requestmapping (value = "/aop) public Class AoPtestClerTroller {@"/"/AOP)) @RequestMapping (value = "/teste", método = requestMethod.get) Teste de resultado público (@RequestParam boolean tlowException) {// case 1 if (throwException) {System.out.println ("Lança uma exceção"); lançar a nova testException ("Mock a Excection um servidor"); } // case 2 system.out.println ("teste ok"); return new resultado () {{this.setId (111); this.setName ("Mock um resultado"); }}; } Resultado da classe estática pública {private int id; nome de string privado; public int getId () {return id; } public void setId (int id) {this.id = id; } public string getName () {return name; } public void setName (nome da string) {this.name = name; }}}Teste a situação normal
Digite o seguinte URL diretamente no navegador e digite: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false 1
Veremos o resultado da saída:
[Aspecto1] Sobre o conselho 1 [aspecto1] antes do conselho ok [aspecto 1] em torno do conselho2 [aspecto1] após aconselhamento [aspecto1]
Exceções de teste
Digite diretamente o seguinte URL no navegador e pressione Enter: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true 1
Veremos o resultado da saída:
[Aspecto1] Sobre o conselho 1 [aspecto1] Antes de advogar uma exceção [aspecto1] após aconselhamento [aspecto1]
para concluir
Quando um método é interceptado por apenas uma classe de aspecto, os conselhos dentro da classe de aspecto serão executados na seguinte ordem:
Situação normal:
Exceção:
Caso 2: O mesmo método é interceptado por várias classes de aspecto
Aqui está um exemplo que é interceptado por duas classes de aspecto.
Em alguns casos, para duas classes de aspecto diferentes, independentemente de seus conselhos usarem o mesmo ponto de ponta ou cortes de pontos diferentes, isso pode causar interceptação pelo mesmo método por várias classes de aspecto. Então, nesse caso, em que ordem os conselhos nessas classes de múltiplos aspectos são executadas? Por favor, veja:
A classe Pointcut permanece inalterada
Adicione uma nova classe de aspecto
teste do pacote; importar org.aspectj.lang.joinpoint; importar org.aspectj.lang.proecedingJoinPoint; importar org.aspectj.lang.annotation.*; importar org.springframework.tereotype.component;@component@aspectoppublic Aspecto2 {@before (valueTyPeTyPoTy.comPOND.CONMENTC (@component@ComponentPublic. {System.out.println ("[aspecto2] antes do conselho"); } @Around (value = "test.pointcuts.aopdemo ()") public void em torno (ProceedingJoinPoint PJP) lança arremesso {System.out.println ("[aspecto2] em torno do conselho 1"); pjp.proeced (); System.out.println ("[aspecto2] em torno do conselho2"); } @AfterReturning (value = "test.pointcuts.aopdemo ()") public void após retornar (junção junção) {System.out.println ("[aspecto 2] após o consultoria"); } @Afterwrlowing (value = "test.pointcuts.aopdemo ()") public void AfterWring (junção junção) {System.out.println ("[aspecto2] conselhos posteriores"); } @After (value = "test.pointcuts.aopdemo ()") public void após (junção junção) {System.out.println ("[aspecto2] conselhos posteriores"); } @After (value = "test.pointcuts.aopdemo ()") public void após (junção junção) {System.out.println ("[aspecto2] após o conselho"); }}O controlador de teste também permanece inalterado
Ainda use o controlador acima. Mas agora os aspectos1 e os aspectos2 interceptam os métodos no controlador.
Continue testando abaixo!
Teste a situação normal
Digite o seguinte URL diretamente no navegador e digite: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false 1
Veremos o resultado da saída:
[Aspecto2] Em torno do conselho 1 [aspecto2] Antes do conselho [Aspecto1] em torno do conselho 1 [aspecto1] antes do conselho ok [aspecto1] em torno do conselho2 [aspecto1] Após o conselho [aspecto1] Após a redução do conselho [aspecto2] em torno do conselho2 [aspecto2] após o consultoria após o retorno
Mas, neste momento, não posso concluir que o aspecto2 é definitivamente executado antes do aspecto1.
Não acredita? Você reinicia o servidor e tenta novamente, talvez veja os seguintes resultados de execução:
[Aspecto1] Sobre o conselho 1 [aspecto1] antes do conselho [aspecto 2] em torno do conselho 1 [aspecto2] antes do conselho ok [aspecto2] em torno do conselho2 [aspecto2] Após o conselho [aspecto2] após o consultoria [aspecto1] em torno do conselho2 [aspecto1] após o consultoria após o retorno
Isto é, neste caso, a ordem de execução de aspecto1 e aspecto2 é desconhecida. Então, como resolvê -lo? Sem pressa, a solução será dada abaixo.
Exceções de teste
Digite diretamente o seguinte URL no navegador e pressione Enter: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true 1
Veremos o resultado da saída:
[Aspecto2] Em torno do conselho 1 [aspecto2] antes do conselho [aspecto 1] em torno do conselho 1 [aspecto1] antes de avisar uma exceção [aspecto1] depois de jogar conselhos [aspectos2] depois de jogar conselhos
Da mesma forma, se você reiniciar o servidor e testá -lo novamente, poderá ver os seguintes resultados:
[Aspecto1] Em torno do conselho 1 [aspecto1] Antes do conselho [Aspecto2] em torno do conselho 1 [aspecto2] Antes de aconselhar uma exceção [aspecto2] Aconselhamento após o conselho [aspecto1] Aconselhamento após o conselho
Ou seja, da mesma maneira, a ordem de execução de aspecto1 e aspecto2 também é indeterminada em circunstâncias excepcionais.
Então, no caso 2, como você especifica a ordem de execução de cada aspecto?
Existem dois métodos:
Não importa qual método seja usado, quanto menor o aspecto, mais ele é executado primeiro.
Por exemplo, adicionamos anotações @Order para APSect1 e Aspect2, respectivamente, como segue:
@Order (5)@componente@Aspecpublic Class Aspect1 {// ...}@order (6)@componente@Aspecpublic class Aspect2 {// ...} Após essa modificação, pode -se garantir que, em qualquer caso, os conselhos em Ascepect1 sejam sempre executados antes do conselho em Ascepect2. Como mostrado na figura abaixo:
Observação
Se dois conselhos idênticos forem definidos para o mesmo ponto (por exemplo, dois @Before) forem definidos, a ordem de execução desses dois conselhos não poderá ser determinada, mesmo se você adicionar a anotação @Order a esses dois conselhos, ela não funcionará. Lembre -se disso.
Para o conselho @around, independentemente de ter um valor de retorno ou não, ele deve ligar para PJP.Proced () dentro do método; Caso contrário, a interface no controlador não será executada, o que também fará com que os conselhos @Before não sejam acionados. Por exemplo, assumimos que, em circunstâncias normais, a ordem de execução é "aspecto2 -> apSect1 -> controlador". Se excluirmos pjp.proeced (); Em @around em aspecto1, então a saída que vemos será:
[Aspecto2] Em torno do conselho 1 [aspecto2] Antes do conselho [Aspecto1] em torno do conselho 1 [aspecto 1] em torno do conselho2 [aspecto1] Após o conselho [aspecto 1] Após o consultoria [aspecto2] em torno do conselho2 [aspecto2] Após a recuperação do conselho
A partir dos resultados, podemos descobrir que a interface no controlador não foi executada e o @BeForeadVice em Ascepect1 também não foi executado.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.