Spring-AOP

Spring-AOP

AOP 面向切面编程,是spring中最核心的技术之一

你可以将业务模块中横向上公共的部分抽取出来,利用spring-aop在你需要的时候为你自动注入,而不需要修改你的源代码,开发中就可以更加专注于业务的开发。

在这里插入图片描述

动态代理和静态代理

静态代理:静态代理需要你手动实现代理类对象。通过和被代理类实现相同的接口的方式,在代理类中调用被代理类的方法,在代理类中编写需要增强的代码。

动态代理:由机器自动的为你生成代理类对象。你只需要定义被代理类对象,被代理类对象实现的接口。

JDK 动态代理

spring的aop实现切面编程的底层技术是使用了动态代理的机制,有两种动态代理的方式,一种是JDK的动态代理,另一种的cglib动态代理,spring默认使用的是JDK动态代理。

注意:JDK动态代理,需要被代理类必须实现接口。

JDK 动态代理代理的是接口

JDK 动态代理的实现是通过Proxy类的newProxyInstance()方法创建一个代理对象,这个方法需要三个参数

  • 参1:被代理类的类加载器 classLoader

  • 参2:被代理类实现的接口(必须实现接口,可以实现多个接口):class<?>[]

  • 参3:代理类处理程序,反射机制自动帮你调用被代理类的需要被代理的方法,在调用方法的前、后可以编写你需要注入的代码


//对代理过程进行了封装,使之变得通用
public class ProxyInvocationHandler implements InvocationHandler {


    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        //通过Proxy 的newProxyInstance()方法得到一个代理对象
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    
    //invoke 方法,调用被代理类的方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //proxy 被代理的对象
        //method 被代理的方法
        //args	方法的参数
		System.out.println("代理了" + proxy.getClass().getName() + "的" + method.getName() + "方法");
        Object result = method.invoke(target, args);

        return result;
    }
}
  • 接口

    public interface ILaoBan {
        void eat();
    
    }
    
  • 实现类

    public class LaoBan implements ILaoBan {
        @Override
        public void eat() {
            System.out.println("吃饭");
        }
    }
    
  • test

    public class LaoBanTest {
    
        @Test
        public void test01 () {
    
            ILaoBan laoBan = new LaoBan();
    
            ProxyInvocationHandler pih = new ProxyInvocationHandler();
            pih.setTarget(laoBan);
            ILaoBan instance = (ILaoBan) pih.getProxyInstance();
            instance.eat();
    
        }
    
    }
    

Spring 实现AOP

AOP的一些术语概念

  • Aspect:切面,一个类,需要注入的代码
  • pointcut:切入点,在被代理类中被增强的方法
  • joinPoint:连接点,被代理类的所有方法
  • weave:织入,就是将代理类中需要增强的方法放入到目标类中去执行的过程
    将原方法与其他类的方法一起调用
  • advice:通知,将代理对象中的方法应用到目标类的过程中产生的结果。

xml配置实现

  • 1、导入依赖的jar包

    <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.9.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.7.2</version>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.2.9.RELEASE</version>
            </dependency>
    
        </dependencies>
    
  • 2、定义一个接口

    public interface IUser {
    
        public void work();
    }
    
  • 目标类实现接口

    public class UserImpl implements IUser {
        @Override
        public void work() {
            System.out.println("写代码");
        }
    }
    
  • 定义一个切面类

    public class MyAdivce {
    
    
        public void bolgAdvice() {
            System.out.println("写完代码写个写个博客!");
        }
    
    }
    
  • 在applicationContext.xml配置文件中配置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.jsu">
                <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
            </context:component-scan>
    
            <bean id="user" class="com.jsu.UserImpl"/>
            <bean id="advice" class="com.jsu.MyAdivce"/>
    
            <aop:config>
    
                <!--配置一个切点,被代理类中具体被增强的方法-->
                <aop:pointcut id="work" expression="execution(public void com.jsu.UserImpl.work())"/>
                <!--配置一个切面 -->
                <aop:aspect ref="advice">
                    <!--将切面中的哪一个方法 注入到被代理类的方法中-->
                    <aop:after method="bolgAdvice" pointcut-ref="work"/>
                </aop:aspect>
            </aop:config>
    
    </beans>
    
  • test

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class AppTest 
    {
    
        @Autowired
        private IUser user;
    
    
        @Test
        public void shouldAnswerWithTrue()
        {
           user.work();
    
        }
    }
    
  • 输出结果

在这里插入图片描述

注解实现

注解实现,可以省去一些xml配置。

注解实现就是在切面类上加上@Aspect注解,在配置文件中开启注解支持自动代理

  • applicationContext.xml

    <?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.jsu">
                <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
            </context:component-scan>
    
            <bean id="user" class="com.jsu.UserImpl"/>
            <bean id="advice" class="com.jsu.MyAdivce"/>
    
    
            <aop:aspectj-autoproxy/>
    
            <!--<aop:config>
    
                &lt;!&ndash;配置一个切点,被代理类中具体被增强的方法&ndash;&gt;
                <aop:pointcut id="work" expression="execution(public void com.jsu.UserImpl.work())"/>
                &lt;!&ndash;配置一个切面 &ndash;&gt;
                <aop:aspect ref="advice">
                    &lt;!&ndash;将切面中的哪一个方法 注入到被代理类的方法中&ndash;&gt;
                    <aop:after method="bolgAdvice" pointcut-ref="work"/>
                </aop:aspect>
            </aop:config>-->
    
    </beans>
    
  • 切面类

    @Aspect
    public class MyAdivce {
    	
    	
    	//前置通知
        @Before("execution(public void com.jsu.UserImpl.work())")
        public void before() {
            System.out.println("写代码前喝个饮料");
        }
    
    	//后置通知
        @After("execution(public void com.jsu.UserImpl.work())")
        public void after() {
            System.out.println("写完代码写个写个博客!");
        }
        
        @Around("execution(public void com.jsu.UserImpl.work()))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕前");
    
            //开始执行切点的方法
            Object proceed = proceedingJoinPoint.proceed();
    
            System.out.println("环绕后");
        }
    
    }
    
  • test
    在这里插入图片描述

expression 表达式

  • (1)什么是切面表达式
    execution([修饰符] 返回值类型 包.类.方法(参数列表) );
  • (2)切面表达式有什么用?
    符合表达式的方法,会被增强
    使用* 表过任意的内容
    使用… 可以表示包与子包下面的类
    使用…可以写在方法(…)表示任意参数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值