Spring泛览二(AOP)

AOP

面向切面编程,通过预编译和运行期动态代理,实现程序功能,是函数式编程的一个衍生范型

AOP实现方式


  1. 动态代理Proxy:接口+实现类
  2. cglib字节码: 实现类 (通过创建目标类的子类来实现功能)

JDK动态代理

该方式必须有接口和实现类,原因是对应回调传参的参数是接口类型

/**
 * 切面类:增加代码 与 切入点 结合
 */
public class MyAspect2 {

    public void before(){
        System.out.println("开启事务...");
    }

    public void after(){
        System.out.println("提交事务...");
    }
}
/**
* 接口
*/
public interface IUserService {

    public void add();

    public void add(User user);

    //切面编程
    public void addUser();
    public void updateUser();
    public void deleteUser();
    public int deleteUser(int id);
}
/**
* 接口实现类
*/
@Service("myUserService")
public class UserServiceImpl implements IUserService {

    @Autowired //spring会自动注入userDao赋值
    private IUserDao userDao;

    @Override
    public void add(User user) {
        System.out.println("service 添加用户:" + user);
        //调用dao
        userDao.add(user);
    }

    @Override
    public void addUser() {
        System.out.println("添加用户。。。。");
    }

    @Override
    public void updateUser() {
        System.out.println("更新用户。。。。");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户。。。。");
    }
    @Override
    public int deleteUser(int id) {
        System.out.println("通过id删除用户");
        return 1;
    }
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public void add() {
        System.out.println("创建用户...." + name);
    }
    public UserServiceImpl() {
        //System.out.println("UserServiceImpl()调用了");
    }
}
/**
* 工厂类
*/
public class MyBeanFactory {

    /**
     * JDK实现代理
     * @return
     */
    public static IUserService createUserService(){
        //1.创建目标对象target
        final IUserService userService = new UserServiceImpl();

        //2.声明切面类对象
        final MyAspect2 aspect = new MyAspect2();

        //3.把切面类2个方法 应用 目标类
        //3.1 创建JDK代理,拦截方法
        /*newProxyInstance(
                ClassLoader loader, 类加载器,写当前类(记住即可)
                Class[] interfaces, 接口,接口的方法会被拦截
                InvocationHandler h) 处理
                */
        IUserService seriviceProxy = (IUserService) Proxy.newProxyInstance(
                MyBeanFactory.class.getClassLoader(),
                //因为此处必须传接口,所以原生jdk动态代理必有有接口
                userService.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //开启事务
                        aspect.before();
                        //方法返回值是 业务方法的返回值
                        Object retObj = method.invoke(userService,args);
                        //System.out.println("拦截返回值:" + retObj);
                        //提交事务
                        aspect.after();
                        return retObj;
                    }
                }
        );
        return seriviceProxy;
    }
}

/**
* 测试方法
*/
@Test
    public void test1() throws Exception {

        //实现AOP编程,使用cglib代理来实现

        StudentService ss = MyBeanFactory.createStudentService();

        ss.delete();
       /* ss.update();
        ss.add();*/

    }

cglib字节码实现AOP

只需要实现类(当然有接口和实现类也可)即可,当然切面对象也不能少即(MyAspect2.java)

public class StudentService {
    public void delete(){
        System.out.println("删除学生");

    }
    public void add(){
        System.out.println("add学生");
    }
    public void update(){
        System.out.println("update学生");
    }
}
public class MyBeanFactory {
    /**
     * cglib实现代理
     * @return
     */
    public static StudentService createStudentService(){
        //1.创建目标对象target
        final StudentService studentService = new StudentService();

        //2.声明切面类对象
        final MyAspect2 aspect = new MyAspect2();

        //3.创建增强对象
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(studentService.getClass());
        //设置回调【拦截】
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                /**
                 * proxy:
                 * proxy代理对象是StudentService的子类
                 */
                aspect.before();
                //方式一:放行方法
                //Object retObj = method.invoke(studentService,args);

                //方式二:等同于方式一,通过代理方法调用父类,好处是解耦了,因为没有引用外部变量
                Object retObj = methodProxy.invokeSuper(proxy,args);//解耦
                System.out.println("拦截.....");
                aspect.after();
                return retObj;
            }
        });

        //创建代理对象
        StudentService serviceProxy = (StudentService) enhancer.create();
        return serviceProxy;
    }
}

Spring的AOP自动和半自动

不论自动还是半自动,目的都是不写生成代理对象的相关方法,例如避免书写上面的MyBeanFactory.java文件

Spring项目中半自动AOP

需要额外添加AOP联盟(规范)、spring-aop(实现)两个jar包


  1. com.springsource.org.aopalliance-1.0.0.jar AOP联盟
  2. spring-aop-3.2.0.RELEASE.jar AOP实现

简单案例





    
    

    
    

    
    
        
        
        
        
        
        
        
        
        
        
    

/**
 * 切面类:增加代码 与 切入点 结合
    务必实现MethodInterceptor
 */
public class MyAspect implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        //拦截方法
        System.out.println("开启事务...");
        //放行
        Object retObj = mi.proceed();
        System.out.println("拦截.....");
        System.out.println("提交事务...");
        return retObj;
    }
}

Spring项目中全自动AOP

需要com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar(织入)
需要添加的索引


  1. xmlns:aop ="http://www.springframework.org/schema/aop"
  2. http://www.springframework.org/schema/aop
  3. http://www.springframework.org/schema/aop/spring-aop.xsd





    
    
    
    
    
    
    
        
        
        
        
    

AspectJ

基本案例

/**
* 切面类
*/
public class MyAspect3{
    public void myBefore(){
        System.out.println("前置通知...");
    }
    public void myAfterReturning(){
        System.out.println("后置通知...");
    }
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知...");
        System.out.println(pjp.getSignature().getName());//切入点就方法名
        System.out.println("开启事务...");
        //放行
        Object retObj = pjp.proceed();
        System.out.println("提交事务...");
        return retObj;
    }
}





    
    

    
    

    
    
        
        
            
            
            
            
            
            
            
            
            
            
            
            
        
    

execution()

语法:execution(修饰符  返回值  包.类.方法名(参数) throws异常)
修饰符,一般省略
    public      公共方法
    *           任意
返回值,不能省略
    void            返回没有值
    String      返回值字符串
    *           任意
包,[省略]
    com.zengqiang.crm           固定包
    com.zengqiang.crm.*.service crm包下面子包任意 (例如:com.zengqiang.crm.staff.service)
    com.zengqiang.crm..         crm包下面的所有子包(含自己)
    com.zengqiang.crm.*.service..   crm包下面任意子包,固定目录service,service目录任意包
类,[省略]
    UserServiceImpl         指定类
    *Impl                   以Impl结尾
    User*                   以User开头
    *                       任意
方法名,不能省略
    addUser                 固定方法
    add*                        以add开头
    *Do                     以Do结尾
    *                       任意
(参数)
    ()                      无参
    (int)                       一个整型
    (int ,int)                  两个
    (..)                        参数任意
throws ,可省略,一般不写。

案例1:
execution(* com.zengqiang.crm.*.service..*.*(..))

案例2:或

AspectJ基于xml的案例

package com.zengqiang.aspect;


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


public class MyAspect {
    public void myPointcut(){}

    public void myBefore(JoinPoint jp){
        System.out.println("1.前置通知..." + jp.getSignature().getName());//连接点方法名
    }

   
    public void myAfterReturning(JoinPoint jp,Object retValue){
        System.out.println("3.后置通知..." +  jp.getSignature().getName());
        System.out.println("返回值:" + retValue);
    }

    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        //ProceedingJoinPoint和JoinPoint区别之一就是ProceedingJoinPoint有放行方法
        System.out.println("2.环绕通知...开启事务..." + pjp.getSignature().getName());
        //放行
        Object retObj = pjp.proceed();
        System.out.println("4.环绕通知....提交事务...");
        return retObj;
    }


    public void myAfterThrowing(JoinPoint jp,Throwable e){
        System.out.println("异常通知..." + jp.getSignature().getName() + "===" + e.getMessage() );
    }

    public void myAfter(JoinPoint jp){
        System.out.println("最终通知..." + jp.getSignature().getName());
    }
}





    
    

    
    

    
    
        
        
            
            

            
            
            

            
            

            
            

            
            

            
            
        
    

AspectJ基于注解的案例

//@Aspect对应 bean.xml中的
@Component
@Aspect //告诉配置文件这是切入点类
public class MyAspect {
    //声明一个公共的切入点
   //等效于 
    @Pointcut("execution(* com.zengqiang.service.UserServiceImpl.*(..))")
    public void myPointcut(){}

    @Before("myPointcut()")
    public void myBefore(JoinPoint jp){
        System.out.println("1.前置通知..." + jp.getSignature().getName());//连接点方法名
        //例如此时test中调用的是userService.deleteUser();方法,则上面jp.getSignature().getName()输出
        //就是deleteUser
    }

    /**
     * 后置通知获取service方法执行后的返回值
     * Object retValue:service方法执行的返回值,如果写了返回值,需要在xml中配置returning
     * @param jp
     */
    // 
    @AfterReturning(pointcut = "myPointcut()",returning = "retValue")
    public void myAfterReturning(JoinPoint jp,Object retValue){
        System.out.println("3.后置通知..." +  jp.getSignature().getName());
        System.out.println("返回值:" + retValue);
    }

    @Around("myPointcut()")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        //ProceedingJoinPoint和JoinPoint区别之一就是ProceedingJoinPoint有放行方法
        System.out.println("2.环绕通知...开启事务..." + pjp.getSignature().getName());
        //放行
        Object retObj = pjp.proceed();
        System.out.println("4.环绕通知....提交事务...");
        return retObj;
    }


    @AfterThrowing(pointcut = "myPointcut()",throwing = "e")
    public void myAfterThrowing(JoinPoint jp,Throwable e){
        System.out.println("异常通知..." + jp.getSignature().getName() + "===" + e.getMessage() );
    }

    @After("myPointcut()")
    public void myAfter(JoinPoint jp){
        System.out.println("最终通知..." + jp.getSignature().getName());
    }
}





    
    

    
    

    
    
        
    

当AspectJ-xml和注解同时存在的执行顺序

大部分情况下,这个顺序对业务没影响,主要注意事务提交和资源释放的顺序。该顺序针对上面AspectJ基于注解的案例中的MyAspect.JAVA


  1. service方法有返回值 + 无异常 + XML

1.前置通知...deleteUser
2.环绕通知...开启事务...deleteUser
通过id删除用户
3.后置通知...deleteUser
返回值:1
4.环绕通知....提交事务...
最终通知...deleteUser


  1. service方法有返回值 + 无异常 + 注解

2.环绕通知...开启事务...deleteUser
1.前置通知...deleteUser
通过id删除用户
4.环绕通知....提交事务...
最终通知...deleteUser
3.后置通知...deleteUser
返回值:1


  1. service方法没有返回值 + 无异常 + XML

1.前置通知...deleteUser
2.环绕通知...开启事务...deleteUser
删除用户。。。。
3.后置通知...deleteUser
返回值:null
4.环绕通知....提交事务...
最终通知...deleteUser


  1. service方法没有返回值 + 无异常 + 注解

2.环绕通知...开启事务...deleteUser
1.前置通知...deleteUser
删除用户。。。。
4.环绕通知....提交事务...
最终通知...deleteUser
3.后置通知...deleteUser
返回值:null



AOP的事务配置

基于xml的形式

 
    
        
        
    
图片1.png
图片2.png

补充:isolation:代表隔离级别,propagation代表传播行为,图上是默认值,其实可以省略不写

基于注解的形式

图片3.png
图片4.png

你可能感兴趣的:(Spring泛览二(AOP))