spring的AOP--面向切面编程
2017-08-15 18:10
531 查看
AOP概念
1、AOP:aspect oriented programming 面向切面编程2、AOP在spring中的作用
提供声明式服务(声明式事务)
允许用户实现自定义切面
3、AOP:在不改变原有代码的情况下,增加新的功能。
4、名词解释:
关注点:增加的某个业务。如日志、安全、缓存、事务、异常处理等。
切 面 :一个关注点的模块化。
连接点:表示一个方法的执行。
通 知 :在切面的某个特定的连接点上执行的动作。
目标对象:被代理的对象--真实对象。
织 入 :把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象。
5、使用spring实现aop
第一种实现方式: 通过spring的api来实现
前置通知
项目结构如下:查看spring中文帮助文档,文档下载地址:《spring中文帮助文档.chm》
中有关于aop通知的介绍,我们现在使用前置通知,从文档中可以知道我们要实现MethodBeforeAdvice,如下图:
Log代码:
package cn.myspring.log; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * 日志切面 */ public class Log implements MethodBeforeAdvice { /** * @param method * :被调用的方法对象 * @param args * : 被调用的方法的参数 * @param target * : 被调用方法的目标对象 */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName() + "的" + method.getName() + " 方法被执行"); } }
UserService代码:
package cn.myspring.service; /** * 抽象角色 */ public interface UserService { public void add() ; public void update() ; public void delete() ; public void search() ; }
UserServiceImpl代码:
package cn.myspring.service; /** * 真实角色 */ public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("增加用户"); } @Override public void update() { System.out.println("修改用户"); } @Override public void delete() { System.out.println("删除用户"); } @Override public void search() { System.out.println("查询用户"); } }
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: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="cn.myspring.service.UserServiceImpl"></bean> <bean id="log" class="cn.myspring.log.Log"></bean> <aop:config> <!-- aop:pointcut切入点配置: execution() : 是表达式; * : 表示所有返回值 ; 位置 : cn.myspring.service.UserServiceImpl ; 方法 : add() ; --> <aop:pointcut expression="execution(* cn.myspring.service.UserServiceImpl.add())" id="pointcut"/> <!-- aop:advisor : 告诉程序,切入点如嵌入的业务有哪些; advice-ref : 对应的公共业务 ; pointcut-ref: 切入点。 --> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> </aop:config> </beans>
Test类代码:
package com.myspring.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.myspring.service.UserService; public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml") ; UserService userService = (UserService) ac.getBean("userService") ; userService.add() ; } }
运行Test类,控制台打印信息:
2017-8-16 10:04:28 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2747ee05: startup date [Wed Aug 16 10:04:28 CST 2017]; root of context hierarchy 2017-8-16 10:04:29 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [beans.xml] 2017-8-16 10:04:29 org.springframework.context.support.ClassPathXmlApplicationContext refresh 警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in class path resource [beans.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Cannot resolve reference to bean 'pointcut' while setting bean property 'pointcut'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pointcut': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in class path resource [beans.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Cannot resolve reference to bean 'pointcut' while setting bean property 'pointcut'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pointcut': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:479) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.myspring.test.Test.main(Test.java:11) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Cannot resolve reference to bean 'pointcut' while setting bean property 'pointcut'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pointcut': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1531) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:92) at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:102) at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:103) at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:248) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1037) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1011) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:473) ... 10 more Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pointcut': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1155) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351) ... 26 more Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1147) ... 32 more Caused by: java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException at java.lang.Class.getDeclaredConstructors0(Native Method) at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389) at java.lang.Class.getConstructor0(Class.java:2699) at java.lang.Class.getDeclaredConstructor(Class.java:1985) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80) ... 33 more Caused by: java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:252) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320) ... 38 more
造成报错的原因是因为缺少两个jar包:aopalliance-1.0.jar和aspectjweaver-1.8.8.jar,
这两个jar包的下载地址:《aop面向切面需要的jar包》
将这两个jar包放到项目中,如图:
然后再次运行Test,控制台打印信息如下:
说明spring的aop产生作用了。
接下里我们在Test代码中增加一行调用delete方法的代码,如下:
package com.myspring.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.myspring.service.UserService; public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml") ; UserService userService = (UserService) ac.getBean("userService") ; userService.add() ; System.out.println("----------------------------"); userService.delete() ; } }
运行Test控制台打印信息如下:
我们发现调用的delete方法,并没有加上日志信息。
这是因为我们在beans.xml配置文件中,aop的日志配置,只配置了add方法,
如图:
如果想要UserServiceImpl类中的所有方法都起作用,那么配置应该改成*号,如下面的代码:
<?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="cn.myspring.service.UserServiceImpl"></bean> <bean id="log" class="cn.myspring.log.Log"></bean> <aop:config> <!-- aop:pointcut切入点配置: execution() : 是表达式; * : 表示所有返回值 ; 位置 : cn.myspring.service.UserServiceImpl ; 方法 : * 表示UserServiceImpl类中的所有方法都起作用 ; --> <aop:pointcut expression="execution(* cn.myspring.service.UserServiceImpl.*())" id="pointcut"/> <!-- aop:advisor : 告诉程序,切入点如嵌入的业务有哪些; advice-ref : 对应的公共业务 ; pointcut-ref: 切入点。 --> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> </aop:config> </beans>
再次运行Test代码,控制台打印信息如下:
可以看到在add方法和delete方法的前面都打印了日志信息。
如果我们的方法有参数,那么就可以在beans.xml配置aop时,写上两个点,如下:
如果是某一个包下面的所有的类的所有方法都要使用aop嵌入日志信息,那么就可以写成如下:
后置通知
从spring中文帮助文档.chm中可以看到后置通知的实现类如下图:在cn.myspring.log包下增加AfterLog类,代码如下:
package cn.myspring.log; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class AfterLog implements AfterReturningAdvice { /** * 目标方法执行后,执行的通知 * * @param returnValue * : 返回值 ; * @param method * : 被调用的方法对象 ; * @param args * : 被调用方法的参数 ; * @param target * : 被调用的方法对象的目标对象 。 */ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName() + "的" + method.getName() + "被成功执行 , 返回值是 :" + returnValue); } }
在beans.xml中配置文件增加afterLog类的配置和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: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="cn.myspring.service.UserServiceImpl"></bean> <bean id="log" class="cn.myspring.log.Log"></bean> <bean id="afterlog" class="cn.myspring.log.AfterLog"></bean> <aop:config> <!-- aop:pointcut切入点配置: execution() : 是表达式; * : 表示所有返回值 ; 位置 : cn.myspring.service.UserServiceImpl ; 方法 : * 表示UserServiceImpl类中的所有方法都起作用 ; --> <aop:pointcut expression="execution(* cn.myspring.service.*.*(..))" id="pointcut"/> <!-- aop:advisor : 告诉程序,切入点如嵌入的业务有哪些; advice-ref : 对应的公共业务 ; pointcut-ref: 切入点。 --> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/> </aop:config> </beans>
测试类Test代码如下:
package com.myspring.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.myspring.service.UserService; public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml") ; UserService userService = (UserService) ac.getBean("userService") ; userService.add() ; } }
运行Test代码,控制台打印信息如下:
AOP的重要性:
spring的aop就是将公共的业务(如:日志、安全等)和领域业务结合。当执行领域业务时,将会把公共业务加进、
来。实现公共业务的重复利用。领域业务更纯粹,程序员专注于领域业务。其本质还是动态代理。
第二种方式实现aop:自定义类来实现
项目结构如图:Log日志类:
package cn.myspring.log;
/**
* 日志切面
*/
public class Log {
public void before() {
System.out.println("---方法执行前---");
}
public void after() {
System.out.println("---方法执行后---");
}
}
UserService类:
package cn.myspring.service;
/**
* 抽象角色
*/
public interface UserService {
public void add() ;
public void update() ;
public void delete() ;
public void search(int a) ;
}
UserServiceImpl类代码:
package cn.myspring.service;
/**
* 真实角色
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void search(int a) {
System.out.println("查询用户"+a);
}
}
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: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="cn.myspring.service.UserServiceImpl"></bean>
<bean id="log" class="cn.myspring.log.Log"></bean>
<aop:config>
<!-- 自定义aop配置
ref : 关联Log日志类;
-->
<aop:aspect ref="log">
<aop:pointcut expression="execution(* cn.myspring.service.*.*(..))" id="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
Test类代码:
package com.myspring.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.myspring.service.UserService; public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml") ; UserService userService = (UserService) ac.getBean("userService") ; userService.add() ; } }
运行Test类,控制台打印信息:
第三种实现方式:通过注解来实现
项目结构如下:Log类代码如下:
package cn.myspring.log;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* 日志切面
*/
@Aspect
public class Log {
@Before("execution(* cn.myspring.service.*.*(..))")
public void before() {
System.out.println("---方法执行前---");
}
@After("execution(* cn.myspring.service.*.*(..))")
public void after() {
System.out.println("---方法执行后---");
}
}
UserServiceImpl代码:
package cn.myspring.service;
/**
* 抽象角色
*/
public interface UserService {
public void add() ;
public void update() ;
public void delete() ;
public void search(int a) ;
}
UserServiceImpl代码:
package cn.myspring.service;
/**
* 真实角色
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void search(int a) {
System.out.println("查询用户"+a);
}
}
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: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="cn.myspring.service.UserServiceImpl"></bean>
<bean id="log" class="cn.myspring.log.Log"></bean>
<!-- 自动配置aop -->
<aop:aspectj-autoproxy />
</beans>
Test类同上,运行后控制台打印信息:
当实现环绕通知时,我们在Log类中增加如下代码:
@Around("execution(* cn.myspring.service.*.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行目标方法
jp.proceed() ;
System.out.println("环绕后");
}
增加后Log类代码如图:
执行Test类代码,控制台打印信息如下:
相关文章推荐
- Spring面向切面编程AOP
- 深入分析JavaWeb 54 -- Spring中的AOP面向切面编程2
- Spring---AOP面向切面编程
- AOP-Spring的面向切面编程
- 使用Spring进行面向切面(AOP)编程
- Spring AOP 面向切面编程相关注解
- 【spring-boot】spring aop 面向切面编程初接触
- 解释通知Spring AOP 面向切面编程
- Spring 面向切面(AOP)编程,注解
- Spring配置过程 (二)面向切面编程AOP
- Spring--AOP--面向切面编程
- spring学习--面向切面编程AOP和AspectJ
- spring_由注解实现AOP面向切面编程_实现动态代理
- SpringAop 9 (面向切面编程,常用于拦截器)
- Spring的AOP-面向切面编程
- 从头认识Spring-1.2 什么是AOP?为什么需要面向切面编程?
- Spring面向切面编程——Spring实现AOP方式——通过注解实现
- Spring AOP的基本原理及面向切面编程的实现
- Spring笔记——使用Spring进行面向切面(AOP)编程
- CGLIB实现AOP代理的测试类,与Spring分离,加深对面向切面编程的理解