一、例子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; } }
UserDAO.java:
package com.cy.dao; import com.cy.model.User; public interface UserDAO { public void save(User user); }
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!"); } }
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"); } }
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;
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; } }
使用例子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"); } }
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!"); } }
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"); } }
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"); } }
运行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: