Spring aop的简化版本

引入依赖

<!--引入依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.9</version>
        </dependency>


    <!--这是lombok依赖-->
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <version>1.18.20</version>
         </dependency>

    <!--这是测试依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.9</version>
        </dependency>

    </dependencies>



配置文件Springconfig

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

   //在这里主要的目的是一个包扫描,这是第一种方法,第二种方法是创建一个配置类进行包扫描
    <context:component-scan base-package="com.biyi"/>

</beans>

不使用代理出现的问题

package com.biyi.service.implment;

import com.biyi.dao.Dao;
import com.biyi.service.UserService;
import com.biyi.user.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class UserServiceImplment implements UserService {

    @Autowired
    private Dao dao;

    @Override
    public void addUser(User user) {
        System.out.println("每个方法都需要写这样相同的代码");

        System.out.println("权限校验");
        System.out.println("事务管理");
        System.out.println("开启事务");
        try {

            dao.addUser(user);
            System.out.println("提交事务");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("事务回滚");
        }finally{
            System.out.println("关闭链接");
        }
    }

    @Override
    public void updateUser(User user) {
        dao.updateUser(user);

        System.out.println("权限校验");
        System.out.println("事务管理");
        System.out.println("开启事务");
        try {

            dao.updateUser(user);
            System.out.println("提交事务");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("事务回滚");
        }finally{
            System.out.println("关闭链接");
        }
        
        
        
    }

    @Override
    public void deleteById(int id) {
         dao.deleteById(id);


    }
}

测试类

package com.biyi.admintest;


import com.biyi.controller.UserController;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:springconfig.xml")
public class AdminTest {

    @Autowired
     private   UserController  userController;

    public void fun1(){
        userController.addUser();
        System.out.println();

    }

}

动态代理

package com.biyi.action;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Poxy {
    public static void main(String[] args) {

        //这是商家的类
       //同样商家是与代理这进行对接

        /*
        * newProxyInstance(ClassLoader loader,代理就是地理star类,目标对象的类加载器  相当于new 目标对象
                           Class<?>[] interfaces,目标对象实现是接口
                           InvocationHandler h)创建代理对象的回调函数
        *
        *
        * */

        //传过来是目标对象是谁,也就是star,真正的目标对象是star,也就是说真正唱歌个或者跳舞的是star
        Star star=new Star();
        //如何拿到类加载器,那么通过getclass
        Class<? extends Star> aClass = star.getClass();

      //说明如果在这里不进行强制类型转换是无法调用sing放方法和dance方法,所以需要进行强制类型转化
      //我们是不是要创建代理对象,就newProxyInstance这一个方法就搞定了,
      //我们要那star的代理对象,star是通过接口进行代理,所以这个地方需要强制类型转换
      //这里aClass.getClassLoader(),类加载器,这里是代理star所以是star的类加载器,所以肯定要传过来star对象
      //getInterfaces(),目标对象实现的接口
      //new InvocationHandler() 创建代理对象的一个回调函数,在这里其实我们不管是接口,我们也直接去new
      Skill dailiobj= (Skill) Proxy.newProxyInstance(aClass.getClassLoader(), aClass.getInterfaces(), new InvocationHandler() {

           //这是匿名内部类,回调函数,在jdk8之后出现了lambad表达式

            /*
            这是创建代理对象的回调函数 invoke 
            * proxy:代理对象
            * method:代理对象的方法,也就是执行功能的方法
            * args:代理对象的方法的参数
            * Throwable:异常处理
            * */

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("商家与经纪人沟通");
                System.out.println("签合同");
                System.out.println("给钱");

                /*
                * Object obj: 目标对象
                * Object... args:参数
                *
                * */

               //Object obj =null;
                     //我们开始执行方法,方法在哪里,在method里面
                    // 其实这里是目标对象,所以在这里的参数
                    Object   obj=method.invoke(star, args);
                    System.out.println("关闭链接");
                return obj;
            }
        });
          //代理对象创建完成,我们去调用代理对象的方法
         //代理对象的方法
        //说明如果在这里不进行强制类型转换是无法调用sing放方法和dance方法,
        dailiobj.sing();
        dailiobj.dance();
    }

}


interface Skill{
void sing();
void dance();

}


//目标类
class Star implements Skill{

    public void sing(){

        System.out.println("唱歌好听");
    }

    public void dance(){

        System.out.println("跳舞");
    }

}

Spring cglib代理

Star star=new Star();
        Class<? extends Star> aClass = star.getClass();


      //    使用cglib进行代理
      //其实cglib和jdk比较相似
      //使用cglib创建代理对象
//通过这个Enhancer类来去帮助我们创建代理对象
    Enhancer enhancer =new Enhancer();
      //在newProxyInstance有三个参数,其实enhancer是一样的
        enhancer.setClassLoader(aClass.getClassLoader());
        enhancer.setInterfaces(aClass.getInterfaces());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
               System.out.println("商家与经纪人沟通");
                System.out.println("签合同");
                System.out.println("给钱")

        Object   obj=method.invoke(star,objects);
        System.out.println("关闭链接");
        return obj;
            }
        });
                   //这里我们依然去拿代理对象
              Skill dailiobj = (Skill) enhancer.create();
              System.out.println(dailiobj.getClass());
        //代理对象的方法
        //说明如果在这里不进行强制类型转换是无法调用sing放方法和dance方法,
        dailiobj.sing();
        dailiobj.dance();

   }

}


interface Skill{
void sing();
void dance();


}


//目标类
class Star implements Skill{

    public void sing(){

        System.out.println("唱歌好听");
    }

    public void dance(){

        System.out.println("跳舞");
    }

}

Spring aop

实现aop

需求实现service逻辑的业务的增强(事务的管理)

其余的代码为三层代码结构的代码

创建切面类

package com.biyi.aspect;


import org.aopalliance.intercept.Invocation;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;

//编写切面类,这个类就是代理类
//当我们编写这个是一个普通类所以我们要实现 
//MethodInterceptor这是aop包里面的接口,不要引错了

@Component
public class MyAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation Invocation) throws Throwable {
      //在这里编写增强/通知(业务逻辑)

        System.out.println("开启事务");
//在这里我们是不是需要写我们的链接点,哪些方法需要增强,其实谁是方法,这里的在这里Invocation.getMethod()执行目标对象的业务功能,在这里增强方法
                   //通过MethodInvocation就可以拿到对象即可getMethod
                   //然后我们要进行切入点,在这里我们要拿到可以增强的方法,
       Method method = Invocation.getMethod();
       
        //执行方法,之前都是通过method.invoke这个方法执行,但是在aop里面是拿不到这个方法,但是,在aop里面封装了一个proceed这个方法进行
        //具体如何拿到需要增强的方法,我们之前都是通过invoke,但是在aop里面我们是拿不到这个方法的,但是底层给我们封装了proceed这个方法
        Object obj = Invocation.proceed();
        System.out.println("提交事务");

        return obj;
    }
}

编写aop代理类的代码之后要告诉我对谁增强,那么就用到了aop的配置

aop的配置

<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.biyi"/>
 <!--配置aop,指定那些类的哪些方法需要被增强
    那么这个有规则
    id的值是ID的名称,
    expression:表达式  1, within 粗粒度  也就是说只能定位到类上 2,excution是相对来说叫细粒度,可以定位到某个方法的

    * com.biyi.service.*.*(..)其中*标示所有这句话说明在com.biyi.service包下的所有方法增强
      <aop:config proxy-target-class="true">
      proxy-target-class="true"jdk代理
      proxy-target-class="false"。cglib代理
      但是我们一般不写
    -->
    <aop:config >
        <aop:pointcut id="point" expression="execution(* com.biyi.service.*.*(..))"/>
   <aop:pointcut id="point" expression="within(com.biyi.service.*)"/><!--关于within的使用由于只能定位到类上所以后面到不能使用-->


        <!--增强什么样的逻辑,也就是我们写的切面,切面类放到容器,在这里引用-->
       <!--配置通知-->
        <aop:advisor advice-ref="myAspect" pointcut-ref="point"/>
    </aop:config>



</beans>

测试类

package com.biyi.admintest;


import com.biyi.controller.UserController;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:springconfig.xml")
public class AdminTest {

    @Autowired
     private   UserController  userController;

    public void fun1(){
        userController.addUser();
        System.out.println();

    }

}

其余的代码为三层代码结构

代码的复用性

其余的就是三层代码结构

下面的这是测试类的代码

在这里插入图片描述

aop的通知

在上面的情况是都执行了一遍,但是有时候只需要部分执行,
比如
在方法执行之前执行,在方法执行之后执行,有时候在方法前后进行管理,那么这种情况就需要用到通知
但是如果我们都将这种通知,写到代理对象中就会出现代码冗余,耦合性高这种情况

aop的5大通知

前置通知
后置通知
环绕通知
最终通知
异常通知

创建新的代理类

package com.biyi.aspect;

import org.springframework.stereotype.Component;

@Component
public class MySecond {

    public void  a(){

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


    }
}

配置类

前置通知

在springconfig文件里面

<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.biyi"/>

   <!-- <aop:config>
        <aop:pointcut id="point" expression="execution(* com.biyi.service.*.*(..))"/>
        <aop:pointcut id="point" expression="within(com.biyi.service.*)"/>由于只能定位到类上所以后面到不能使用&ndash;&gt;

        <aop:advisor advice-ref="myAspect" pointcut-ref="point"/>
    </aop:config>-->

    <!--Spring6大通知
    前置通知(就是业务执行之前进行使用),比如权限校验
    后置通知(就是业务执行之前进行使用),比如日志管理
    环绕通知(就是业务执行之前后进行使用)某个方法执行的时间等
    最终通知(方法执行结束之后进行使用)
    异常通知就是在方法中出现之后有异常出现进行使用
    引介通知
    -->
    <aop:config>
        <!--对于service是开启事务-->
        <aop:pointcut id="point1" expression="execution(* com.biyi.service.*.*(..))"/>
        <!--对于dao是日志管理-->
        <aop:pointcut id="point2" expression="execution(* com.biyi.dao.*.*(..))"/>

        <!--使用Spring到通知进行增强-->
        <aop:aspect ref="mySecond">
            <aop:before method="a" pointcut-ref="point1"/>

        </aop:aspect>



    </aop:config>
    
    

</beans>

创建新的代理类

package com.biyi.aspect;

import org.springframework.stereotype.Component;

@Component
public class MySecond {

    public void  a(){

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


    }
}

执行结果

在这里插入图片描述

后置通知

配置类

<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.biyi"/>

   <!-- <aop:config>
       &lt;!&ndash; <aop:pointcut id="point" expression="execution(* com.biyi.service.*.*(..))"/>&ndash;&gt;
        <aop:pointcut id="point" expression="within(com.biyi.service.*)"/>&lt;!&ndash;由于只能定位到类上所以后面到不能使用&ndash;&gt;

        <aop:advisor advice-ref="myAspect" pointcut-ref="point"/>
    </aop:config>-->

    <!--Spring6大通知
    前置通知(就是业务执行之前进行使用),比如权限校验
    后置通知(就是业务执行之前进行使用),比如日志管理
    环绕通知(就是业务执行之前后进行使用)某个方法执行的时间等
    最终通知(方法执行结束之后进行使用)
    异常通知就是在方法中出现之后有异常出现进行使用
    引介通知
    -->
    <aop:config>
        <!--对于service是开启事务-->
        <aop:pointcut id="point1" expression="execution(* com.biyi.service.*.*(..))"/>
        <!--对于dao是日志管理-->
        <aop:pointcut id="point2" expression="execution(* com.biyi.dao.*.*(..))"/>

        <!--使用Spring到通知进行增强-->
        <aop:aspect ref="mySecond">
            <aop:before method="a" pointcut-ref="point1"/>
            <aop:after method="after" pointcut-ref="point2"/>
        </aop:aspect>

    </aop:config>
</beans>

代理类

package com.biyi.aspect;

import org.springframework.stereotype.Component;

@Component
public class MySecond {

    public void  a(){

        System.out.println("前置通知before");
    }

    public void after(){
        System.out.println("后置通知after");
    }
}

环绕通知和异常通知

配置文件

<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.biyi"/>

   <!-- <aop:config>
       &lt;!&ndash; <aop:pointcut id="point" expression="execution(* com.biyi.service.*.*(..))"/>&ndash;&gt;
        <aop:pointcut id="point" expression="within(com.biyi.service.*)"/>&lt;!&ndash;由于只能定位到类上所以后面到不能使用&ndash;&gt;

        <aop:advisor advice-ref="myAspect" pointcut-ref="point"/>
    </aop:config>-->

    <!--Spring6大通知
    前置通知(就是业务执行之前进行使用),比如权限校验
    后置通知(就是业务执行之前进行使用),比如日志管理
    环绕通知(就是业务执行之前后进行使用)某个方法执行的时间等
    最终通知(方法执行结束之后进行使用)
    异常通知就是在方法中出现之后有异常出现进行使用
    引介通知
    -->
    <aop:config>
        <!--对于service是开启事务-->
        <aop:pointcut id="point1" expression="execution(* com.biyi.service.*.*(..))"/>
        <!--对于dao是日志管理-->
        <aop:pointcut id="point2" expression="execution(* com.biyi.dao.*.*(..))"/>

        <!--使用Spring到通知进行增强-->
        <aop:aspect ref="mySecond">
            <aop:before method="a" pointcut-ref="point1"/>
            <aop:after method="after" pointcut-ref="point2"/>
            <aop:around method="around" pointcut-ref="point1"/>
            <aop:after-returning method="afterreturning" pointcut-ref="point1"/>
            <aop:after-throwing method="afterthrow" pointcut-ref="point1" throwing="e"/>
        </aop:aspect>
    </aop:config>
    
  
</beans>

代理类

package com.biyi.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Component
public class MySecond {

    public void  a(){

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


    }


    public void after(){

        System.out.println("后置通知after");
    }


    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("方法执行前");
        Object obj = joinPoint.proceed();
        System.out.println("方法执行后");

        return obj;
    }

    public void afterreturning(){

System.out.println("最终通知");


    }

public void afterthrow(Exception e){
//注意:这个throw是只有异常才能执行,否则不执行,比如在service里面System.out.println(1/0)执行就会执行这个异常

        System.out.println(1/0);
}


}
package com.biyi.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Component
public class MySecond {

    public void  a(){

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


    }


    public void after(){

        System.out.println("后置通知after");
    }


    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("方法执行前");
        Object obj = joinPoint.proceed();
        System.out.println("方法执行后");

        return obj;
    }

    public void afterreturning(){

System.out.println("最终通知");


    }

public void afterthrow(Exception e){
//注意:这个throw是只有异常才能执行,否则不执行,比如在service里面System.out.println(1/0)执行就会执行这个异常

         System.out.println("throwing");
}


}

注解通知开发

package com.biyi.aspect;


import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect//标示这个类就是一个切面类
public class MyThird {

    @Pointcut("execution(* com.biyi.service.*.*(..))")
    public void print1(){}


    @Before("print1()")
    public void before(){
    System.out.println("这是前置通知");

    }
@After("print1()")
 public void after(){

        System.out.println("后置通知after");
    }

   @Around("print1()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("方法执行前");
        Object obj = joinPoint.proceed();
        System.out.println("方法执行后");

        return obj;
    }
     @AfterReturning("print1()")
    public void afterreturning(){

System.out.println("最终通知");


    }
@afterthrowing("print1()")
public void afterthrow(){
//注意:这个throw是只有异常才能执行,否则不执行,比如在service里面System.out.println(1/0)执行就会执行这个异常

         System.out.println("throwing");
}




}

在配置类里面添加开启aop注解驱动

在这里插入图片描述

  <!--开启aop的驱动-->
    <aop:aspectj-autoproxy/>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值