5.aop+动态代理

JDK动态代理

  • 创建接口和实现类
  • 创建代理类实现InvocationHandler这个接口,使用构造器传入被代理类对象,并且实现invoke方法,该方法第一个参数卵用没有,第二个参数是方法,第三个参数是方法的传参
  • 要想使用方法增强就先得调用原来的方法们,可以利用反射来解决,于是利用第二个参数Method.invoke方法传入对象和参数,前后再添加增强的逻辑
  • 在使用代理类的时候使用Proxy.newInstance()方法返回接口引用,第一个参数是类加载器,第二个参数需要放入接口的数组,第三个参数填入代理类对象
public class PeopleDaoImpl implements PeopleDao {
    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public String update(String id) {
        return id;
    }
}

代理类:

public class JDKProxy {
    public static void main(String[] args) {
        //接口的数组
        Class[] interfaces = {PeopleDao.class};
        PeopleDaoImpl peopleDao=new PeopleDaoImpl();
        //该方法返回指定接口的代理类实例(类加载器,增强方法使用的类的接口,代理类)
        PeopleDao dao = (PeopleDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new PeopleDaoProxy(peopleDao));
        int add=dao.add(1,2);
        System.out.println(add);
    }
}
//创建代理对象代码
class PeopleDaoProxy implements InvocationHandler {
    Object obj;
    //有参构造传递
    public PeopleDaoProxy(Object obj){
        this.obj=obj;
    }
    //添加增强的代码,把创建的是谁的代理对象,需要把谁给传递进来
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前的处理
        System.out.println("方法执行之前"+method.getName()+"传递的参数"+ Arrays.toString(args));
        //被增强的方法执行
        Object res=method.invoke(obj,args);
        //方法之后的处理
        System.out.println("方法执行之后"+obj);
        return res;
    }
}

结果

方法执行之前add传递的参数[1, 2] 方法执行之后day506AOP.PeopleDaoImpl@5197848c 3

AOP

AOP面向方面/切面编程:在不通过修改源代码的方式添加新的功能 

AOP底层原理:动态代理

两种代理情况

  • 第一种有接口:使用jdk动态代理----proxy类有newProxyInstance方法参数(类加载器,增强方法所在的类,实现接口invocationHandler,创建代理对象,写增强的方法) * 创建接口实现类的代理对象
  • 无接口:使用CGLIB动态代理创建当前类子类的代理对象

AOP术语:

  • 连接点:所有可以被增强的方法
  • 切入点:实际中被增强的方法
  • 通知(增强):实际增强的逻辑部分,通知有多种类型:
  • 前置:连接点之前执行 后置:之后 环绕:之前之后 异常:异常的时候执行最终 finally不管有没有都执行
  • 切面:把通知应用到切入点的过程就叫做切面(是一个动作)

AOP操作:

AspectJ实现AOP:

注解实现:切入点表达式:知道对哪个类里面的哪个方法进行增强 * 语法结构:execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))

  • 举例一:对com.atguigu.dao.BookDao类里的add进行增强 *表示任意修饰符 返回类型可以省略 * execution(* com.atguigu.dao.BookDao.add(..))
  • 参数列表用..来表示对包里所有的方法进行增强 execution(* com.atguigu.dao.BookDao.*(..))
  • 对包里所有类所有方法进行增强 execution(* com.atguigu.dao.*.*(..))

使用aop需要在spring的依赖上添加一个依赖

        
            org.aspectj
            aspectjweaver
            1.9.6
        
        
            org.springframework
            spring-webmvc
            5.2.12.RELEASE
        

 需要被增强的方法

public interface UserService {
    void add();
}
public class UserServiceImpl implements UserService {

    public void add() {
        System.out.println("方法执行");
    }
}

自定义切面类

@Aspect//标注他为一个切面
public class DiyAopLog  {
    @Before("execution(* wym.testaop.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("执行前");
    }
    @After("execution(* wym.testaop.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("执行后");
    }
    //环绕增强中,可以给定一个参数,代表要获取处理切入的点
    @Around("execution(* wym.testaop.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前");
        //执行方法
        Object pro=joinPoint.proceed();
        System.out.println("环绕后");
    }
}

xml文件



    
    

    
    

 测试代码

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //使用的必须是接口而不是实现类
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        userService.add();
    }

环绕前

执行前

方法执行

执行后

环绕后

Aop执行顺序

Spring4:

正常情况: @Around前环绕通知–>@Before–>@Around后环绕通知–>@After–>@AfterReturning
异常情况:@Around前环绕通知–>@Before–>@After–>@AfterThrowing

Spring5:

正常情况:@Around前环绕通知–>@Before–>@AfterReturning–>@After–>@Around后环绕通知
异常情况:@Around前环绕通知–>@Before–>@AfterThrowing–>@After 

你可能感兴趣的:(Spring,aop,spring,java,设计模式,jdk)