1. Visão geral
Em sistemas gerais, quando fazemos algumas operações importantes, como fazer login no sistema, adicionar usuários, excluir usuários etc., precisamos persistir esses comportamentos. Neste artigo, implementamos a inserção de log por meio de anotações personalizadas da Spring AOP e Java. Esta solução tem menos intrusão ao negócio original e é mais flexível na realização
2. Definições de classe relacionadas de toras
Abstraímos o log em duas classes: módulo funcional e tipo de operação
Use classes de enumeração para definir o módulo do módulo de função Moduletype, como o Módulo de Estudante e Usuário
Public Enum Moduletype {default ("1"), // Valor padrão aluno ("2"), // professor de estudante ("3"); // Módulo de usuário ModuleType Private ModuleType (String Index) {this.module = index; } módulo de sequência privada; public String getModule () {return this.module; }}Use uma classe de enumeração para definir o tipo de operação: EventType. Como login, adicione, excluir, atualizar, excluir etc.
public Enum EventType {padrão ("1", "padrão"), add ("2", "Add"), update ("3", "update"), delete_single ("4", "excluir-single"), login ("10", "login"), login_out ("11", "Login_out"); private EventType (índice da string, nome da string) {this.name = name; this.Event = index; } evento de sequência privada; nome de string privado; public string getEvent () {return this.event; } public string getName () {return name; }}3. Defina anotações relacionadas ao log
3.1. @Logenable
Aqui, definimos a quantidade de interruptor do log. Somente quando esse valor for verdadeiro na classe, a função de log nesta classe será ativada.
@Documentado @retention (retentionpolicy.runtime) @target ({elementType.type}) public @Interface Logenable { / ** * se true, o logEvent abaixo da classe será ativado, caso contrário * @return * / boolean logenable () default true;}3.2. @Logevent
Definição do log aqui. Se esta anotação for anotada na classe, esse parâmetro será usado como o valor padrão para todos os métodos da classe. Se a anotação estiver no método, só funcionará para este método
@Documentado@retention (retentionpolicy.runtime) @target ({java.lang.annotation.ElementType.method, elementType.type}) public @Interface LogEvent {ModuleType Module () default moduletype.default; // O módulo ao qual o log pertence EventType Event () padrão eventtype.default; // Tipo de evento de log Tipo string desc () padrão ""; // Descrição Informações}3.3. @LogKey
Se esta anotação estiver em um método, os parâmetros de todo o método serão salvos no formato JSON. Se esta anotação for anotada tanto no método quanto na classe, a anotação no método substitui o valor da classe.
@Target ({elementType.field, elementType.parameter})@retention(retionPolicy.runtime)@documentEdPublic @interface logkey {string keyname () padrão ""; // o nome da chave booleana isUserID () padrão false; // Se esse campo é o IDSID desta operação, aqui é omitido boolean IsLog () padrão true; // se é adicionado ao log}4. Defina a classe de processamento de log
4.1. Logadmmodel
Defina a classe que contém informações de log
classe pública Logadmmodel {private longo id; private string userID; // opera o nome de usuário de string privado do usuário; String privada AdmModel; // Module Private String Admvent; // operação data privada criada; // Operação Conteúdo Private String ADMOTCONTENT; // Operação Conteúdo Private String Desc; // Com observação definida/omitida}4.2. ILOGMANAGER
Defina a classe de interface ilogmanager para processamento de logs
Podemos armazenar logs no banco de dados ou enviar logs para abrir o middleware, se Redis, MQ, etc. Cada classe de processamento de log é uma classe de implementação dessa interface
interface pública ILOGMANAGER { / *** Módulo de processamento de log* @param paramLogadMBean* / void deallog (Logadmmodel paramLogadMbean);}4.3. DblogManager
Classe de implementação do ILOGManager para armazenar logs. Apenas armazenamento simulado aqui
@ServicePublic Classe dblogManager implementa o ILOGManager {@Override public void Deallog (Logadmmodel paramLogadMBean) {System.out.println ("Armazene o login no banco de dados, o conteúdo do log é o seguinte:" + json.tojSonstring (paramLogadMBean); }}5. Configuração da AOP
5.1. Logaspect define a classe AOP
Anote esta aula com @Aspect
Use @PointCut para definir os métodos de pacote e classe para interceptar
Usamos @around para definir o método
@Componente @Aspecpublic Classe Logaspect {@AUTOWIRED LOGINFOGENERAÇÃO DE LOGINFOGENAÇÃO DE @Autowired Private ILogManager LogManager; @PointCut ("Execution (*com.hry.spring.mvc.aop.log.service ..*.*(..))") public void ManagerLogPoint () {} @Alound ("gerenteLogPoint ()) public objeto em torno do managerLogPoint (prosseguir JP) Throwstable ()). }} ao redor do ManagerLogPoint: o principal processo de negócios do método principal
1. Verifique se a classe do método de interceptação é anotada por @Logenable. Nesse caso, a lógica do log será seguida, caso contrário, a lógica normal será executada.
2. Verifique se o método de interceptação é @logevent. Nesse caso, a lógica do log será seguida, caso contrário, a lógica normal será executada.
3. Obtenha o valor mediano do @LOGEVENT com base no método de obtenção e gera alguns parâmetros do log. O valor de @logevent é definido na classe como o valor padrão
4. Ligue para o processo do LoginFogeneationManagerLogMessage para preencher outros parâmetros no log. Falaremos sobre esse método mais tarde.
5. Realize chamadas comerciais normais
6. Se a execução for bem -sucedida, o LogManager executa o log (apenas registramos os registros da execução bem -sucedida aqui e você também pode definir os registros da falha na gravação)
@Around ("gerenciadorLogPoint ()") Objeto público ao redor do ManagerLogPoint (ProceedingJoinPoint JP) lança throwable {class Target = jp.getTarget (). GetClass (); // obtém logenable logenable Logenable = (logenable) Target.getAnnotation (logenable.class); if (logenable == null ||! logenable.Logenable ()) {return jp.proeced (); } // Obtenha o LogEvent na classe como o valor padrão LogEvent LogEventClass = (LogEvent) Target.getAnnotation (logEvent.class); Método método = getInvokedMethod (JP); if (método == null) {return jp.proeced (); } // Obtenha o logEvent no método logEvent LogEventMethod = Method.getAnnotation (LogEvent.class); if (logEventMethod == null) {return jp.proeced (); } String opTevent = logEventMethod.Event (). GetEvent (); String optModel = logEventMethod.module (). GetModule (); String desc = logEventMethod.desc (); if (logEventClass! = null) {// Se o valor no método for o valor padrão, substitua -o pelo valor global. optevent = optevent.equals (eventtype.default)? LogEventClass.Event (). getEvent (): optevent; optmodel = optmodel.equals (moduletype.default)? logEventClass.module (). getModule (): optmodel; } Logadmmodel logBean = new Logadmmodel (); logbean.setadmmodel (optmodel); logbean.setAdMevent (optevent); logbean.setDesc (DEC); logbean.setCreatedate (new Date ()); LoginFogeneation.processingManagerLogMessage (JP, LogBean, Método); Objeto returnObj = jp.proeced (); if (optevent.equals (eventtype.login)) {// TODO Se ele estiver conectado, você precisará julgar se é bem -sucedido com base no valor de retorno. Se for bem -sucedido, adicione logs. O julgamento aqui é relativamente simples se (returnObj! = Null) {this.logmanager.Dealllog (LogBean); }} else {this.logmanager.deallog (logbean); } return returnObj; } / ** * Obtenha o método de solicitação * * @param jp * @return * / public Method getinVokedMethod (junção jp) {// parâmetros do método de chamada list ClassList = new ArrayList (); for (objeto obj: jp.getargs ()) {classlist.add (obj.getclass ()); } Classe [] argscls = (classe []) classlist.toarray (nova classe [0]); // o nome chamado Nome String MethodName = JP.getSignature (). GetName (); Método método = nulo; tente {Method = jp.getTarget (). getClass (). getMethod (MethodName, argscls); } catch (noschmethodException e) {e.printStackTrace (); } método de retorno; }}6. A solução para aplicar a solução acima na prática
Aqui simulamos o negócio dos alunos e usamos as anotações acima para aplicá -las a eles e interceptar os logs.
6.1. ISTUDENTSERVICE
Classe de interface de negócios, execute o general Crud
interface pública ISTUDENTSERVICE {void DeletebyId (string ID, string a); int save (StudentModel studentmodel); Void Update (StudentModel StudentModel); Void QuerybyId (string ID);}6.2. StudentServiceImpl:
@Logenable: @LogEvent define todos os métodos de módulo na classe de interceptação de log de inicialização. Outras informações sobre @logeven definem o log. @Service @logenable // Iniciar o log Interception @logevent (module = moduleType.student) classe public StudentServiceImpl implementa ISTUDENTSERVICE {@Override @logevent (Event = EventType.Delete_Single, desc = "Delete Record") / Adicione log identificador public public) System.out.printf (this.getClass () + "DeletebyId ID =" + ID); } @Override @logevent (event = eventtype.add, desc = "salvar registro") // Adicione o identificador de log public int save (StudentModel studentModel) {System.out.printf (this.getclass () + "salvar =" + json.tojSonstring (studentmodel)); retornar 1; } @Override @logevent (event = eventType.UpDate, desc = "Atualizar registro") // Adicione o identificador de log Public Void Update (StudentModel studentModel) {System.out.printf (this.getclass () + "Salvar update =" + json.tojSonstring (studentmodel)); } // Nenhum identificador de log @Override public void querybyId (string id) {System.out.printf (this.getClass () + "querybyId id =" + id); }}Execute a classe de teste e imprima as seguintes informações para indicar que nossa configuração de anotação de log está ativada:
Armazene os logs no banco de dados e o conteúdo do log é o seguinte:
{"Admvent": "4", "Admmodel": "1", "ADMOTCONTENT": "{/" Id/":/" 1/"}", "CreatedEt": 1525779738111, "Desc": "Delete Record"}7 Código
Veja abaixo o código detalhado acima
Código do GitHub, tente usar a tag v0.21, não use o mestre, porque não posso garantir que o código mestre permanecerá inalterado