spring随笔(AOP)

AOP术语

1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3**.PointCut** 切入点:已经被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5 . Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7 . Aspect(切面): 是切入点pointcut和通知advice的结合,一个切入点和一个通知,组成成一个特殊的面。

cglib

package com.spring.cglb;
//切面类
public class MyAspect {
    public void before() {
        System.out.println("开启事物");
    }

    public void after() {
        System.out.println("提交事务");
    }

}
package com.spring.cglb;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Service;

@Service
public class MyBeanFactory {
    public static UserServiceImpl getServiceInstance() {
        final MyAspect aspect = new MyAspect();
        final UserServiceImpl userService = new UserServiceImpl();
        Enhancer e = new Enhancer();
        e.setSuperclass(userService.getClass());
        //回调函数
        e.setCallback(new MethodInterceptor() {

            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy proxymethod)
                    throws Throwable {
                aspect.before();
                Object obj = method.invoke(userService, args);
                aspect.after();
                return obj;
            }
        });
        // 创建代理类
        UserServiceImpl proxyService = (UserServiceImpl) e.create();
        return proxyService;
    }
}

AOP联盟通知类型

AOP联盟为通知Advice定义了org.aopalliance.aop.Advice
Spring按照通知Advice在目标类方法的连接点位置,可以分为5类
前置通知 org.springframework.aop.MethodBeforeAdvice
在目标方法执行前实施增强
后置通知 org.springframework.aop.AfterReturningAdvice
在目标方法执行后实施增强
环绕通知 org.aopalliance.intercept.MethodInterceptor
在目标方法执行前后实施增强
异常抛出通知 org.springframework.aop.ThrowsAdvice
在方法抛出异常后实施增强
引介通知 org.springframework.aop.IntroductionInterceptor
在目标类中添加一些新的方法和属性

Aop半自动代理

package com.spring.semiauto;

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

//切面类 在切面l类中确定通知类型  实现不同的接口 使用环绕通知 

public class MyAspect implements MethodInterceptor {
    public void before() {
        System.out.println("开启事物");
    }

    public void after() {
        System.out.println("提交事务");
    }

    @Override
    public Object invoke(MethodInvocation m) throws Throwable {
        this.before();
        // 手动执行目标方法
        Object obj = m.proceed();
        this.after();
        return obj;
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- target类 -->
    <bean id="UserServiceId" class="com.spring.semiauto.UserServiceImpl"></bean>
    <!-- 切面类 -->
    <bean id="MyAspect" class="com.spring.semiauto.MyAspect"></bean>
    <!-- 创建代理类
       使用工厂bean FractoryBean,底层调用getObjiect() ,返回bean
       proxyFractoryBean 用于创建代理工厂 生成特殊代理对象
       interfaces   确定代理的接口们
       target          注入目标类
       interceptorNames  切面类名称
       optimize :强制使用cglib
              底层的原理是:
              判断有没有接口 有接口使用jdk代理
              没有接口使用cglib代理
              声明optimize 使用cglib       

     -->

    <bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean" >
        <property name="interfaces" value="com.spring.semiauto.UserService"></property>
        <property name="target" ref="UserServiceId"></property>
        <property name="interceptorNames" value="MyAspect"></property>

    </bean>


</beans>

AOP自动代理

导入jar包:这里写图片描述 切入点表达式jar
引入命名空间

<?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: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/aop 
         http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- target类 -->
    <bean id="UserService" class="com.spring.auto.UserServiceImpl"></bean>
    <!-- 切面类 -->
    <bean id="MyAspect" class="com.spring.auto.MyAspect"></bean>
    <!-- aop编程 -->
    <aop:config>
    <aop:pointcut expression="execution(* com.spring.auto.UserServiceImpl.*(..))" id="Mypoincut"/>
    <aop:advisor advice-ref="MyAspect" pointcut-ref="Mypoincut"/>
    </aop:config>
</beans>

AspectJ

aspectj 通知类型

before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行
afterReturning:后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以阻止方法的执行必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常

aspectj编程

这里写图片描述

package com.spring.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

//切面类
public class MyAspect {
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("前置通知:" + "方法名。。。。" + name);
    }

    public void afterReturning(JoinPoint jp, Object ret) {
        System.out.println("后置通知");
        System.out.println(ret);

    }

    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("最终通知:" + "方法名。。。。" + name);
    }

    public Object MyArround(ProceedingJoinPoint pjp, Object ret) throws Throwable {
        this.before(pjp);
        Object object = pjp.proceed();
        this.afterReturning(pjp, ret);
        return object;
    }

    public void MyAfterThrowable(JoinPoint jp, Throwable e) {
        String name = jp.getSignature().getName();
        System.out.println("异常:" + name + "..." + e.getMessage());

    }
}
<?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: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/aop 
         http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 目标类 -->
    <bean id="UserService" class="com.spring.aspectj.UserServiceImpl"></bean>
    <!-- 切面类 -->
    <bean id="MyAspect" class="com.spring.aspectj.MyAspect"></bean>

    <!-- 前置通知配置 ref 引入切面 pointcut 切入点表达式 此表达式只能当前通知使用 pointcut 切入点引用 可与其他通知共享 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut
                expression="execution(* 
        com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:before method="before" pointcut-ref="Mypointcut" />
        </aop:aspect>
    </aop:config>
    <!-- 最终通知 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut
                expression="execution(* 
        com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:after method="after" pointcut-ref="Mypointcut" />
        </aop:aspect>
    </aop:config>
    <!-- 环绕通知 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:around method="MyArround" pointcut-ref="Mypointcut" />
        </aop:aspect>
    </aop:config>
    <!-- 异常通知 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:after-throwing method="MyAfterThrowable"
                pointcut-ref="Mypointcut" throwing="e" />
        </aop:aspect>
    </aop:config>
    <!-- 后置通知 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:after-returning method="afterReturning"
                pointcut-ref="Mypointcut" returning="ret" />

        </aop:aspect>
    </aop:config>


</beans>

使用注解

//切面类
@Component
@Aspect
public class MyAspect {
    //创建切入点表达式
    @Pointcut("execution(* com.spring.aop_annotation.UserServiceImpl.*(..))")
    public void MyPointCut() {

    }

    @Before("MyPointCut()")
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("前置通知:" + "方法名。。。。" + name);
    }

    @AfterReturning(value = "MyPointCut()", returning = "ret")
    public void afterReturning(JoinPoint jp, Object ret) {
        System.out.println("后置通知");
        System.out.println(ret);

    }

    @After("MyPointCut()")
    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("最终通知:" + "方法名。。。。" + name);
    }

    @Around("MyPointCut()")
    public Object MyArround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("前");
        Object object = pjp.proceed();
        System.out.println("后");
        return object;
    }

    @AfterThrowing(value = "MyPointCut()", throwing = "e")
    public void MyAfterThrowable(JoinPoint jp, Throwable e) {
        String name = jp.getSignature().getName();
        System.out.println("异常:" + name + "..." + e.getMessage());

    }
}
<?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:aop="http://www.springframework.org/schema/aop"
    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/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.spring.aop_annotation"></context:component-scan>
    <!-- 使aop注解生效 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章