chapter05-aop-aspectJ(基于aspectJ实现AOP)

chapter05-aop-aspectJ(基于aspectJ实现AOP),第1张

chapter05-aop-aspectJ(基于aspectJ实现AOP)

目录

目录

使用aspectJ框架完成aop的实现

新建maven项目

加入maven依赖

spring容器,创建 对象

Student类

一.前置通知的使用@Before

 1.创建目标类(接口和它的实现类)

2.切面类

 3.MyApp

 二.后置通知的使用@AfterReturning

1.创建目标类(接口和实现类)

 2.切面类

3.MyApp 

三.环绕通知(@Around) 

1.创建目标对象(接口和实现类)

2.创建切面类

3.MyApp

四.异常通知@AfterThrowing

1.创建目标对象(接口和实现类) 

2.创建切面类

3.MyAPP

 五.最终通知@After

 1.创建目标类(接口和实现类)

2.切面类

3.MyApp

 六.@Pointcut切入点的复用

1.创建目标类(接口和实现类) 

2. 切面类

 3.MyApp


使用aspectJ框架完成aop的实现
ch05-aop-aspectj:使用aspectj框架实现aop。
使用aop:目的是给已经存在的一些类和方法,增加额外的功能。前提是不改变原来类的代码。

使用aspectj实现aop的基本步骤:
1.新建maven项目
2.加入依赖
   1)spring依赖
   2)aspect依赖
   3)junit单元测试
3.创建目标类:接口和它的实现类
    要做的是给类中的方法增加功能

4.创建切面类:普通类
   1)在类的上面加入 @Aspect
   2)在类中定义方法,方法就是切面要执行的功能代码
   在方法的上面加入aspectj中的通知注解,例如 @Before
   有需要指定切入点表达式execution()

5.创建spring的配置文件,声明对象,把对象交给容器统一管理。
    声明对象你可以使用注解,或者xml配置文件
    1)声明目标对象
    2)声明切面类对象
    3)声明aspectj框架中的自动代理生成器标签。
        自动代理生成器:用来完成代理对象的自动创建功能。

6.创建测试类,从spring容器中获取目标对象(实际上就是代理对象)。
    通过代理实现方法,实现aop的功能增强。
新建maven项目 加入maven依赖



  4.0.0

  edu.tjdz
    
  ch05-aop-sapectj
  1.0-SNAPSHOT

  
    UTF-8
    1.8
    1.8
  

  
    
      junit
      junit
      4.11
      test
    

      
      
          org.springframework
          spring-context
          5.2.5.RELEASE
      
      
      
          org.springframework
          spring-aspects
          5.2.5.RELEASE
      
  

  

  

spring容器,创建 对象



    
    
    

    
    

    
    

    

    
Student类
package edu.tjdz.ba02;

public class Student {

    private String name;
    private int age;

    public Student(){
        System.out.println("Spring会调用类的无参数构造方法创建对象");
    }

    public void setEmail(String email){
        System.out.println("setEmail="+email);
    }

    
    public void setName(String name) {
        System.out.println("setName="+name);
        this.name = name.toUpperCase();
    }

    public void setAge(int age) {
        System.out.println("setAge="+age);
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}
一.前置通知的使用@Before

首先是创建好切面类后在切面类的上面加入@Aspect注解

在方法之上加入@Before表示前置通知,它有属性value,其值是一个切入点表达式:

参数包括:(红色表示为必须写的)

        execution("修饰符 返回值类型 包.类.方法名(参数..) throws异常")

  修饰符(举例):一般省略

     *       任意

    public     公共访问

  返回值(举例):

    void       无返回值

    String      返回值是字符串类型

    *       返回值任意

  包(举例):      

    com.xx.user.dao    固定包

    com.xx.*.dao          com.xx下的任意包中的dao包

    com.xx.user.dao..  包括dao下所有子包中

  类(举例):

    UserDaoImpl   具体类

    User*         以User开头类

    *User         以User结尾类

    *           任意类

  方法(举例):

    addUser      具体方法

    *        任意方法

    *User      以add结尾方法

    add*       以add开头方法

  参数(无参):

    ()         无参

    (..)       任意参数

    (String,int)     1个String和1个int类型的参数

    (int)        1个int类型参数

  throws,可省略一般不写

在@aspect类中会有使用:

Aspect类的命名及其方法的命名详见标题2切面类中的注释

例如:

        @Aspect

        public class MyAspectJ{

                @Before(* * edu.tjdz.*.*.doSome(..) Exception)

                public void myBefore(){

                        System.out.println("前置通知方法");

                }

        }

 1.创建目标类(接口和它的实现类)
package edu.tjdz.ba01;

public interface SomeService {
    void doSome(String name,Integer age);
}
package edu.tjdz.ba01;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("====目标方法doSome()====");
    }

    public void doOther(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("====目标方法doOther()====");
    }
}
2.切面类
package edu.tjdz.ba01;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.util.Date;


@Aspect
public class MyAspect {
    

    

   

    

    

    

    

    

    

    
    @Before(value="execution(* *..SomeServiceImpl.doSome(String,Integer))")
    public void myBefore2(JoinPoint jp){
        //获取方法的完整定义
        System.out.println("方法的签名(定义)="+jp.getSignature());
        System.out.println("方法的名称="+jp.getSignature().getName());
        //获取方法的实参
        Object [] args = jp.getArgs();
        for(Object arg :args){
            System.out.println("参数="+arg);
        }
        //就是在切面要执行功能代码
        System.out.println("5====>前置通知,切面功能:在目标方法之前输出执行时间:"+new Date());
    }
}
 3.MyApp

有接口的默认采用的是JDK的动态代理

若想在有接口的情况下依旧使用Cglib的代理方式,需要在spring配置文件中加入

package edu.tjdz;

import edu.tjdz.ba01.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest01 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ac.getBean("someService");

        //proxy:com.sun.proxy.$Proxy0
        //proxy:com.sun.proxy.$Proxy8 : JDK的动态代理
        System.out.println("proxy:"+proxy.getClass().getName());

        //通过代理对象执行方法,实现目标方法的执行,增强了功能
        proxy.doSome("李四",20);
    }
}
 二.后置通知的使用@AfterReturning

在方法执行之后执行

1.创建目标类(接口和实现类)
package edu.tjdz.ba02;

public interface SomeService {
    void doSome(String name, Integer age);

    String doOther(String name,Integer age);

    Student doOther2(String name,Integer age);
}
package edu.tjdz.ba02;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("====目标方法doSome()====");
    }

    @Override
    public String doOther(String name, Integer age) {
        System.out.println("====目标方法doOther()====");
        return "abcd";
    }

    @Override
    public Student doOther2(String name, Integer age) {
        Student student = new Student();
        student.setName("lisi");
        student.setAge(20);
        return student;
    }

}
 2.切面类
package edu.tjdz.ba02;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;


@Aspect
public class MyAspect {
    

    
    @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther2(..))",
                    returning = "res")
    public void myAfterReturing(JoinPoint jp,Object res){
        //Object res:目标方法执行之后的返回值,根据返回值做你的切面的功能处理
        System.out.println("后置通知方法的定义:"+jp.getSignature());
        System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
        if(res.equals("abcd")){
            //制作一些功能
        }else{
            //做其他功能
        }

        //修改目标方法的返回值,看一下是否会影响 最后的方法调用的结果
        if(res != null){
            res = "Hello Aspectj";
        }
    }

    @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther2(..))",
            returning = "res")
    public void myAfterReturing2(Object res){
        //Object res:是目标方法执行后的返回值,根据返回值做你的切面的处理功能
        System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);

        //修该目标方法的返回值,看一下是否会影响 最后调用方法输出的结果
        //如果修改了res的内容,属性值等,是不是会影响最后的调用结果呢

        Student student = new Student();
        student.setName("张飞");
        student.setAge(60);
        res = student;
    }
}
3.MyApp 
package edu.tjdz;

import edu.tjdz.ba02.SomeService;
import edu.tjdz.ba02.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest02 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ac.getBean("someService");

        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        String str = proxy.doOther("张三",20);
        System.out.println(str);

    }

    @Test
    public void test02(){
        String config = "applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ac.getBean("someService");

        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        Student str = proxy.doOther2("张三",20);
        System.out.println(str);

    }
}
三.环绕通知(@Around) 

还绕通知等同于JDK动态代理的,InvocationHandler接口

环绕通知:经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务
环绕通知方法定义格式
*  1.public
*  2.必须有一个返回值,推荐使用Object
*  3.方法名称自定义
*  4.方法有参数,固定参数 ProceedingJoinPoint,相当于invoke中的Method()
1.创建目标对象(接口和实现类)
package edu.tjdz.ba03;

import edu.tjdz.ba02.Student;

public interface SomeService {
    void doSome(String name, Integer age);

    String doOther(String name, Integer age);

    Student doOther2(String name, Integer age);

    String doFirst(String name,Integer age);
}
package edu.tjdz.ba03;

import edu.tjdz.ba02.Student;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("====目标方法doSome()====");
    }

    @Override
    public String doOther(String name, Integer age) {
        System.out.println("====目标方法doOther()====");
        return "abcd";
    }

    @Override
    public Student doOther2(String name, Integer age) {
        Student student = new Student();
        student.setName("lisi");
        student.setAge(20);
        return student;
    }

    @Override
    public String doFirst(String name, Integer age) {
        System.out.println("==========业务方法doFirst()=======");

        return "doFirst";
    }

}
2.创建切面类
package edu.tjdz.ba03;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.util.Date;


@Aspect
public class MyAspect {
    

    
    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {

        String name = "";
        //获取第一个参数值
        Object [] args = pjp.getArgs();
        if(args != null && args.length >1){
            Object arg = args[0];
            name= (String)arg;
        }

        //环绕通知
        Object result = null;
        System.out.println("环绕通知:在目标方法之前,输出时间:"+new Date());
        //1.目标方法的调用
        if("zhangsan".equals(name)){
            //符合条件,调用目标方法
            result = pjp.proceed(); //method.invoke(); Object result = doFirst();
        }
        System.out.println("环绕通知:在目标方法之后,提交事务");
        //2.在目标方法的前或者后加入功能

        //修改目标方法的执行结果,影响方法的最后调用结果
        if(result != null){
            result = "Hello AspectJ AOP";
        }

        //返回方法的执行结果
        return result;
    }
}
3.MyApp
package edu.tjdz;

import edu.tjdz.ba03.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest03 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ac.getBean("someService");

       String str = proxy.doFirst("zhangsan",20);  //proxy.invoke();
      //String str = proxy.myAround("zhangsan",20);
       System.out.println(str);
    }

}
四.异常通知@AfterThrowing 1.创建目标对象(接口和实现类) 
package edu.tjdz.ba04;

import edu.tjdz.ba02.Student;

public interface SomeService {
    void doSome(String name, Integer age);

    String doOther(String name, Integer age);

    Student doOther2(String name, Integer age);

    String doFirst(String name, Integer age);

    void doSecond();
}
package edu.tjdz.ba04;

import edu.tjdz.ba02.Student;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("====目标方法doSome()====");
    }

    @Override
    public String doOther(String name, Integer age) {
        System.out.println("====目标方法doOther()====");
        return "abcd";
    }

    @Override
    public Student doOther2(String name, Integer age) {
        Student student = new Student();
        student.setName("lisi");
        student.setAge(20);
        return student;
    }

    @Override
    public String doFirst(String name, Integer age) {
        System.out.println("==========业务方法doFirst()=======");
        return "doFirst";
    }

    @Override
    public void doSecond() {
        //System.out.println(10/0);
        System.out.println("=========执行业务方法doSecond()==");
    }

}
2.创建切面类
package edu.tjdz.ba04;



import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;



@Aspect
public class MyAspect {
    

    
    @AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))",
            throwing = "ex")
    public void myAfterThrowing(Exception ex){
        System.out.println("异常通知:方法发生异常时,执行:"+ex.getMessage());
        //发送邮件,短信,通知开发人员

    }

}
3.MyAPP
package edu.tjdz;

import edu.tjdz.ba04.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest04 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ac.getBean("someService");

        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        proxy.doSecond();
    }

}
 五.最终通知@After  1.创建目标类(接口和实现类)
package edu.tjdz.ba05;

import edu.tjdz.ba02.Student;

public interface SomeService {
    void doSome(String name, Integer age);

    String doOther(String name, Integer age);

    Student doOther2(String name, Integer age);

    String doFirst(String name, Integer age);

    void doSecond();

    void doThird();
}
package edu.tjdz.ba05;

import edu.tjdz.ba02.Student;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("====目标方法doSome()====");
    }

    @Override
    public String doOther(String name, Integer age) {
        System.out.println("====目标方法doOther()====");
        return "abcd";
    }

    @Override
    public Student doOther2(String name, Integer age) {
        Student student = new Student();
        student.setName("lisi");
        student.setAge(20);
        return student;
    }

    @Override
    public String doFirst(String name, Integer age) {
        System.out.println("==========业务方法doFirst()=======");
        return "doFirst";
    }

    @Override
    public void doSecond() {
        //System.out.println(10/0);
        System.out.println("=========执行业务方法doSecond()==");
    }

    @Override
    public void doThird() {
        System.out.println("执行业务方法doThird()"+10/0);
    }

}
2.切面类
package edu.tjdz.ba05;



import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;



@Aspect
public class MyAspect {
    

    
    @After(value = "execution(* *..SomeServiceImpl.doThird(..))")
    public void myAfter() {
        System.out.println("执行最终通知:总是会被执行");
        //一般做资源清理工作的

    }

}
3.MyApp
package edu.tjdz;

import edu.tjdz.ba05.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest05 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ac.getBean("someService");

        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        proxy.doThird();
    }

}
 六.@Pointcut切入点的复用

定义和管理切入点,如果你的项目中有多个切入点表达式是重复的,可以复用的。

@Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))")
private void mypt(){
    //无需代码
}

放其他通知想使用这个通知的时候,直接给value值给一个方法名就可以使用

@Before(value = "mypt()")
public void myBefore() {
    System.out.println("前置通知,在目标方法之前执行的");
}
1.创建目标类(接口和实现类) 
package edu.tjdz.ba06;

import edu.tjdz.ba02.Student;

public interface SomeService {
    void doSome(String name, Integer age);

    String doOther(String name, Integer age);

    Student doOther2(String name, Integer age);

    String doFirst(String name, Integer age);

    void doSecond();

    void doThird();
}
package edu.tjdz.ba06;

import edu.tjdz.ba02.Student;

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name,Integer age) {
        //给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
        System.out.println("====目标方法doSome()====");
    }

    @Override
    public String doOther(String name, Integer age) {
        System.out.println("====目标方法doOther()====");
        return "abcd";
    }

    @Override
    public Student doOther2(String name, Integer age) {
        Student student = new Student();
        student.setName("lisi");
        student.setAge(20);
        return student;
    }

    @Override
    public String doFirst(String name, Integer age) {
        System.out.println("==========业务方法doFirst()=======");
        return "doFirst";
    }

    @Override
    public void doSecond() {
        //System.out.println(10/0);
        System.out.println("=========执行业务方法doSecond()==");
    }

    @Override
    public void doThird() {
        System.out.println("执行业务方法doThird()");
    }

}
2. 切面类
package edu.tjdz.ba06;



import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;



@Aspect
public class MyAspect {

    @After(value = "execution(* *..SomeServiceImpl.doThird(..))")
    public void myAfter() {
        System.out.println("执行最终通知:总是会被执行");
        //一般做资源清理工作的
    }

    @Before(value = "mypt()")
    public void myBefore() {
        System.out.println("前置通知,在目标方法之前执行的");
    }

    
    @Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))")
    private void mypt(){
        //无需代码
    }

}
 3.MyApp
package edu.tjdz;

import edu.tjdz.ba06.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest06 {

    @Test
    public void test01(){
        String config = "applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ac.getBean("someService");

        System.out.println("proxy:"+proxy.getClass().getName());
        //通过代理对象执行方法,实现目标方法执行时,增强了功能
        proxy.doThird();
    }

}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5609209.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存