马士兵Spring-AOP-Aspect例子使用(1)

一、例子1:                                                        

1.工程结构:

2.

User.java:

package com.cy.model;

public class User {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}
View Code

UserDAO.java:

package com.cy.dao;

import com.cy.model.User;

public interface UserDAO {
    public void save(User user);
}
View Code

UserDAOImpl.java:

package com.cy.dao.impl;

import org.springframework.stereotype.Component;

import com.cy.dao.UserDAO;
import com.cy.model.User;

@Component
public class UserDAOImpl implements UserDAO {

    public void save(User user) {
        //Hibernate
        //JDBC
        //XML
        //NetWork
        System.out.println("user saved!");
        //throw new RuntimeException("exeption!");
    }

}
View Code

UserService.java:

package com.cy.service;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.cy.dao.UserDAO;
import com.cy.model.User;

@Component("userService")
public class UserService {
    
    @Resource
    private UserDAO userDAO;  
    
    public void init() {
        System.out.println("init");
    }
    
    public void add(User user) {
        userDAO.save(user);
    }
    
    
    public UserDAO getUserDAO() {
        return userDAO;
    }
    
    public void setUserDAO( UserDAO userDAO) {
        this.userDAO = userDAO;
    }
    
    public void destroy() {
        System.out.println("destroy");
    }
}
View Code

LogInterceptor.java:

package com.cy.aop;

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

@Aspect
@Component
public class LogInterceptor {
    
    /**
     * execution 专门的方法的切入语法;
     *               可以很方便的指定加到哪个/哪些方法上;
     * execution: 方法的执行;UserDAOImpl.save方法执行的时候;
     *               UserDAOImpl.save方法一执行,先把下面的方法before()加到前面 @Before
     */
    @Before("execution(public void com.cy.dao.impl.UserDAOImpl.save(com.cy.model.User))")
    public void before() {
        System.out.println("method before");
    }
}

beans.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-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
           
    <context:annotation-config />
    <context:component-scan base-package="com.cy"/>
    
    <!-- 在spring容器的初始化过程中,会将com.cy下面的所有类都会扫描,
        扫描的时候发现@Component,将这个类初始化;
        同时发现@Aspect,发现这是一个切面逻辑,可以把它切到其他类的方法上面去;
            发现@Befored定义了下;在执行execution中的方法前面加入逻辑
     -->
    <aop:aspectj-autoproxy />
 
</beans>

测试代码:

UserServiceTest.java:

package com.cy.service;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.cy.model.User;

public class UserServiceTest {
    
    @Test
    public void testAdd() throws Exception {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        UserService service = (UserService)ctx.getBean("userService");
        System.out.println(service.getClass());
        service.add(new User());
        ctx.destroy();
    }
}

运行结果:

一些概念:                                                          

二、例子2:                                                    

1.一些织入点语法:

1.the execution of any public method:
execution(public * *(..))
第1个*            任何返回值:
第2个*             *(..)任何类的任何方法     

2.the execution of any method with a name beginning with "set":
execution(* set*(..))
 set*(..)        以set开头的任何方法

3.the execution of any method defined by the AccountService interface:
execution(* com.xyz.service.AccountService.*(..))
任何返回值;
com.xyz.service.AccountService类下面的任何方法;

4.the execution of any method defined in the service package:
execution(* com.xyz.service.*.*(..))

5.the execution of any method defined in the service package or a sub-package:
execution(* com.xyz.service..*.*(..))
com.xyz.service下面的包,子包,不管子包多少层;里面的任何类任何方法;

6.any join point (method execution only in Spring AOP) within the service package:
within(com.xyz.service.*)
method execution only in Spring AOP  spring自身也实现了一套AOP的语法;它也支持使用Aspect的语法来实现;
大部分情况下用不到spring自身的AOP;
View Code

2.各种各样类型的Advice:

1.Before advice

2.After returning advice
After returning advice runs when a matched method execution returns normally. It is declared using the @AfterReturning annotation:
只要这个方法正常执行完了,会执行我们的AfterReturning
如:
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
    // ...
 }

3.After throwing advice
After throwing advice runs when a matched method execution exits by throwing an exception. It is declared using the @AfterThrowing annotation:
当一个方法执行抛出异常的时候,抛出了任何异常,就会执行@AfterThrowing
如:
@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
    // ...
  }

4.After (finally) advice
执行你的方法时候是写try catch finally;catch到异常的时候是执行@AfterThrowing;最后一定会执行finally;

5.Around advice
around环绕;前面可以加逻辑,后面也可以加逻辑;
如:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {

  @Around("com.xyz.myapp.SystemArchitecture.businessService()")
  public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // start stopwatch  加了自己的逻辑;
    Object retVal = pjp.proceed();        //想让程序继续执行,必须调pjp.proceed(),程序才会继续运行;可以参考责任链设计模式;
   //struts2的Interceptor也是这么用的;
    // stop stopwatch  后面加自己的逻辑
    return retVal;
  }
}
View Code

使用例子1:

LogInterceptor.java:

package com.cy.aop;

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

@Aspect
@Component
public class LogInterceptor {
    
    /**
     * execution    方法运行
     * com.cy.dao下面包括它的子包下面,任何类的任何方法;返回值任何类型
     */
    @Before("execution(public * com.cy.dao..*.*(..))")
    public void before() {
        System.out.println("method before");
    }
    
    
    /**
     * @AfterReturning 方法正常执行完成之后
     * 
     */
    @AfterReturning("execution(public * com.cy.dao..*.*(..))")
    public void afterReturning() {
        System.out.println("method after returning");
    }
    
}

运行UserServiceTest.java:---  console:

使用例子2:afterThrowing:

LogInterceptor.java:

package com.cy.aop;

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

@Aspect
@Component
public class LogInterceptor {
    
    @Before("execution(public * com.cy.dao..*.*(..))")
    public void before() {
        System.out.println("method before");
    }
    
    @AfterThrowing("execution(public * com.cy.dao..*.*(..))")
    public void afterThrowing() {
        System.out.println("method after throwing");
    }

}
View Code

UserDAOImpl.java中手动抛出一个异常:

@Component
public class UserDAOImpl implements UserDAO {

    public void save(User user) {
        //Hibernate
        //JDBC
        //XML
        //NetWork
        System.out.println("user saved!");
        throw new RuntimeException("exeption!");
    }

}
View Code

console:

使用例子3:@Around:

LogInterceptor.java:

package com.cy.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogInterceptor {
    
    @Before("execution(public * com.cy.dao..*.*(..))")
    public void before() {
        System.out.println("method before");
    }
    
    @Around("execution(public * com.cy.dao..*.*(..))")
    public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("method around start");
        pjp.proceed();
        System.out.println("method around end");
    }

}
View Code

console:

使用例子4:

把切点定义到UserService.java中的add方法上:

LogInterceptor.java:

package com.cy.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogInterceptor {
    
    @Before("execution(public * com.cy.service..*.add(..))")
    public void before() {
        System.out.println("method before");
    }
    
    @Around("execution(public * com.cy.dao..*.*(..))")
    public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("method around start");
        pjp.proceed();
        System.out.println("method around end");
    }

}
View Code

运行junit但是报错了:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in file [E:jdbcWorkspacespring_aopincomcyserviceUserService.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.
因为UserService没有实现接口;
一个类如果实现了接口,spring采用jdk自带的Proxy和InvocationHandler来产生动态代理;
这个类如果没有实现接口,它会用直接操作二进制码的类库,也就是CGLIB来帮你产生代理的代码;
 
加入CGLIB的jar包:
 
console:
 
原文地址:https://www.cnblogs.com/tenWood/p/6810855.html