A. aspectj框架的aop开发方式有哪几种
使用aspectj实现aop有两种方式:
(1)基于aspectj的xml配置;
(2)基于aspectj的注解方式;
基于aspectj的xml配置:
(1)导入相关的AOP的jar包
(2)创建Spring核心配置文件,导入aop的约束
(3)使用表达式配置切入点
常用的表达式:
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
(4)代码测试
基于aspectj的注解方式:
(1)导入与AOP相关的jar包
(2)创建对象:
(3)开启Aop操作:
(4)在增强类使用注解@Aspect,在方法上使用注解完结增强配置。
(5)测试代码
B. aop注解和xml配置方式的区别
注解和xml配置没有区别,目的都是为了注入。事务我不知道还有注解实现的方式,从来都是直接配置在文件里。
C. java编程中的AOP和IOC分别是什么呢,什么时候用呢
控制反转(IOC)
(理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”)
1、Ioc—Inversion of Control:即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
2、谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象即由Ioc容器来控制对象的创建。
谁控制谁?当然是IoC 容器控制了对象。
控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
3、为何是反转,哪些方面反转了: 有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象。
为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转。
哪些方面反转了?依赖对象的获取被反转了。
还是不明白没事,下面搞个简单案例来说就懂啦 !!!
例子:当我们在任何一个有实际开发意义的程序项目中,我们会使用很多类来描述他们特有的功能,并且通过类与类之间的相互协作来完成特定的业务逻辑。这个时候,每个类都需要负责管理与自己有交互的类的引用和依赖,代码将会变的异常难以维护和极高的高耦合。而IOC的出现正是用来解决这个问题,我们通过IOC将这些依赖对象的创建、协调工作交给spring容器去处理,每个对象值需要关注其自身的业务逻辑关系就可以了。在这样的角度上来看,获得依赖的对象的方式,进行了反转,变成了由spring容器控制对象如何获取外部资源(包括其他对象和文件资料等)。
总的来说:IOC就是通过在Xml配置文件里依赖注入来解决代码问题。
IOC的注入类型有几种?主要可以划分为三种:构造函数注入、属性注入和接口注入。Spring支持构造函数注入和属性注入
面向切面(AOP)
(面向切面编程,AOP其实只是OOP的补充而已,AOP基本上是通过代理机制实现的。)
我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。
我们都知道 Java 是 OOP-面向对象编程的,它有自己的优势,也有自己的不足。比如说:在我们开发中,都会有一条业务主线(即客户的需求)。而我们要做的就是实现这个主线上的需求。我们在实现这些功能的时候,经常要干一些额外的不可避免的事情,比如事务的管理,日志的记录等,就很繁杂且代码量增多,所以 Spring 提供了另一种角度来思考程序结构,也就是把这一些事情剥离出来,然后适时适地的把它们加入到我们的代码中,比如说 声明式事务管理的时候,我们在 service 层检测到save*、update*这些方法要被调用的时候,我们先进行开启事务什么的,这就是AOP,面向编程的思想。
AOP的术语:
1、通知(Advice):就是你想要的功能,也就是上面说的 安全,事物,日志等。你给先定义好把,然后在想用的地方用一下
2、连接点(JoinPoint):这个更好解释了,就是spring允许你使用通知的地方,那可真就多了,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点.其他如aspectJ还可以让你在构造器或属性注入时都行,不过那不是咱关注的,只要记住,和方法有关的前前后后(抛出异常),都是连接点。
3、切入点(Pointcut):上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个连接点了对把,但是你并不想在所有方法附近都使用通知(使用叫织入,以后再说),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
4、切面(Aspect):切面是通知和切入点的结合。现在发现了吧,没连接点什么事情,连接点就是为了让你好理解切点,搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
5、引入(introction):允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗
6、目标(target):引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。
7、代理(proxy):怎么实现整套aop机制的,都是通过代理,这个一会给细说。
8、织入(weaving):把切面应用到目标对象来创建新的代理对象的过程。有3种方式,spring采用的是运行时,为什么是运行时,后面解释。
D. spring注解与配置文件,哪个更好
注解比较方便,但企业开发一般用xml配置的,这样可以解藕,也不用修改程序(不然要重新编译了,太麻烦了),对于比较大的程序,这个是很重要的,所以,建议用xml配置
E. spring配置aop的方式有哪些
在Spring中实现AOP根据版本不同,可以有大致四种配置方式。现简单列一下。在介绍Spring的AOP配置方式前,先要注意Spring中Advisor的概念。在Spring中Advisor是Advice和Pointcut的结合,但它还不是AOP概念上的Aspect。因为在Spring中Advisor还是Spring用来生成Aspect对象的一个原型,根据配置的不同,Spring可以只对某个类生成Aspect,也可以对所有的类生成Aspect。1. 基于xml配置文件的代理配置方式这种方式在2.0以后很少用了,原因是配置项过多,过于繁琐。但对于理解Spring AOP还是很有帮助的1.1 定义通知<bean id="advice" class="yourAdviceImpl" />1.2 定义切点要定义一个切点,可以选择使用正则表达式方式声明的切点或者AspectJ方式声明的切点。对正则表达式切点,使用Perl5RegexpMethodPointcut或JdkRegexpMethodPointcut(Java 1.4以上版本,不需要Jakarta ORO的支持了);对AspectJ切点,使用AspectJExpressPointcut<bean id="pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="pattern" value="yourRegularExpression" /></bean><bean id="pointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut"> <property name="expression" value="yourAspectJExpression" /></bean>1.3 定义通知者DefaultPointcutAdvisor是Spring提供的默认通知者,它需要提供通知和切点的引用。Spring也提供了RegexpMethodPointcutAdvisor和来对应两种声明切点的方式,不用再单独定义切点。<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="advice" /> <property name="pointcut" ref="pointcut" /></bean><bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="advice" /> <property name="pattern" value="yourRegularExpression" /></bean><bean id="advisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcut"> <property name="advice" ref="advice" /> <property name="expression" value="yourAspectjExpression" /></bean>1.4 定义ProxyFactoryBean<bean id="yourBean" class="org.springframework.aop.framework.ProxyFactoryBean> <property name="target" ref="yourTargetBean" /> <property name="interceptorNames" value="advisor" /> <property name="proxyInterfaces" value="interfaceClass" /></bean>interceptorNames和proxyInterfaces都是数组属性,所以可以声明要使用的一个list,也可以让Spring自动把单个值转化为数组上面明确定义了要对那个targetBean应用代理生成切面实例。如果不想限制targetBean,可以让Spring为所有匹配切点声明的bean生成切面实例,这样就不用一个个定义ProxyFactoryBean了,只需要定义<bean class="org.springframework.aop.framework.autoproxy." />这是一个BeanPostProcessor,所以Spring会自动识别并在bean的声明周期使用2 利用2.0以后使用aop标签<aop:config> <aop:aspect ref=""> <aop:pointcut id="performance" expression="execution(* *.perform(..))" /> <aop:before method="" pointcut-ref="performance" /> <aop:before method="" pointcut="execution(* *.perform(..))" /> <aop:after-returning method="" pointcut="execution(* *.perform(..))" /> <aop:after-throwing method="" pointcut="execution(* *.perform(..))" /> </aop:aspect></aop:config>3 利用Annotation3.1 利用@Aspect将一个POJO类声明为一个切面。3.2 定义切点@Pointcut("execution(* *.perform(..))")public void performance(){}通过@Pointcut定义的切点的名字就是它所注解的方法的名字,因此例子中的切点名字是performance()。这里声明的performance()方法实际圣只是一个标记,为@Pointcut提供附加的点,并不要求有实际意义。3.3 定义通知对要执行切面的方法,通过@Before("performance()"),@AfterReturning("performance()")来定义通知。注意这里提供的切点名称,是performance(),而不是performance如果对上面的两点不是很理解,也可以省略@Pointcut,而将AspectJ表达式直接定义在@Before等通知中,将上面的两步合为一步,如@Before("execution(* *.perform(..))")3.4 通知Spring创建代理<aop:aspectj-autoproxy>这实际上相当于声明了一个,从而根据@Pointcut声明的切点来自动代理匹配的bean实例4 在Spring中结合进AspectJ对于超出Spring AOP支持范围的,可以采用这种方式。只需要在Spring中配置AspectJ的Class实例时让Spring能够获得AspectJ类的实例就可以了,比如<bean class="a_aspectj_class" factory-method="aspectOf"> <preperty …. /></bean>
F. spring 中的AOP是怎么实现的
1使用ProxyFactoryBean的代理2隐式使用ProxyFactoryBean的aop代理实现了BeanPostProcessor,它将自动检查advisor的pointcut是否匹配bean的方法,如果匹配会替换bean为一个proxy,并且应用其advice。3使用注解的aop代理xml中增加了一个<aop:aspectj-autoproxy />,它创建了在spring中,这个类将自动代理匹配的类的放方法。和上个例子中做同样的工作。4使用aop配置文件的自动代理采用这种方法,不用加<aop:aspectj-autoproxy />
G. spring中aop全注解时配置类怎么写
先说注解,使用注解配置Spring AOP总体分为两步,第一步是在xml文件中声明激活自动扫描组件功能,同时激活自动代理功能(同时在xml中添加一个UserService的普通服务层组件,来测试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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><!– 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 –><context:component-scan base-package="cn.ysh.studio.spring.aop"/><!– 激活自动代理功能 –><aop:aspectj-autoproxy proxy-target-class="true"/><!– 用户服务对象 –><bean id="userService" class="cn.ysh.studio.spring.aop.service.UserService" /></beans>
第二步是为Aspect切面类添加注解:
package cn.ysh.studio.spring.aop.aspect;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;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切面Bean* @author Shenghany* @date 2013-5-28*///声明这是一个组件@Component//声明这是一个切面Bean@Aspectpublic class ServiceAspect {private final static Log log = LogFactory.getLog(ServiceAspect.class);//配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点@Pointcut("execution(* cn.ysh.studio.spring.aop.service..*(..))")public void aspect(){ }/** 配置前置通知,使用在方法aspect()上注册的切入点* 同时接受JoinPoint切入点对象,可以没有该参数*/@Before("aspect()")public void before(JoinPoint joinPoint){if(log.isInfoEnabled()){log.info("before " + joinPoint);}}//配置后置通知,使用在方法aspect()上注册的切入点@After("aspect()")public void after(JoinPoint joinPoint){if(log.isInfoEnabled()){log.info("after " + joinPoint);}}//配置环绕通知,使用在方法aspect()上注册的切入点@Around("aspect()")public void around(JoinPoint joinPoint){long start = System.currentTimeMillis();try {((ProceedingJoinPoint) joinPoint).proceed();long end = System.currentTimeMillis();if(log.isInfoEnabled()){log.info("around " + joinPoint + " Use time : " + (end – start) + " ms!");}} catch (Throwable e) {long end = System.currentTimeMillis();if(log.isInfoEnabled()){log.info("around " + joinPoint + " Use time : " + (end – start) + " ms with exception : " + e.getMessage());}}}//配置后置返回通知,使用在方法aspect()上注册的切入点@AfterReturning("aspect()")public void afterReturn(JoinPoint joinPoint){if(log.isInfoEnabled()){log.info("afterReturn " + joinPoint);}}//配置抛出异常后通知,使用在方法aspect()上注册的切入点@AfterThrowing(pointcut="aspect()", throwing="ex")public void afterThrow(JoinPoint joinPoint, Exception ex){if(log.isInfoEnabled()){log.info("afterThrow " + joinPoint + " " + ex.getMessage());}}}
测试代码:
package cn.ysh.studio.spring.aop;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.support.;import cn.ysh.studio.spring.aop.service.UserService;import cn.ysh.studio.spring.mvc.bean.User;/*** Spring AOP测试* @author Shenghany* @date 2013-5-28*/public class Tester {private final static Log log = LogFactory.getLog(Tester.class);public static void main(String[] args) {//启动Spring容器ApplicationContext context = new ("applicationContext.xml");//获取service组件UserService service = (UserService) context.getBean("userService");//以普通的方式调用UserService对象的三个方法User user = service.get(1L);service.save(user);try {service.delete(1L);} catch (Exception e) {if(log.isWarnEnabled()){log.warn("Delete user : " + e.getMessage());}}}}
控制台输出如下:
INFO [spring.aop.aspect.ServiceAspect:40] before execution(User cn.ysh.studio.spring.aop.service.UserService.get(long))INFO [spring.aop.service.UserService:19] getUser method . . .INFO [spring.aop.aspect.ServiceAspect:60] around execution(User cn.ysh.studio.spring.aop.service.UserService.get(long)) Use time : 42 ms!INFO [spring.aop.aspect.ServiceAspect:48] after execution(User cn.ysh.studio.spring.aop.service.UserService.get(long))INFO [spring.aop.aspect.ServiceAspect:74] afterReturn execution(User cn.ysh.studio.spring.aop.service.UserService.get(long))INFO [spring.aop.aspect.ServiceAspect:40] before execution(void cn.ysh.studio.spring.aop.service.UserService.save(User))INFO [spring.aop.service.UserService:26] saveUser method . . .INFO [spring.aop.aspect.ServiceAspect:60] around execution(void cn.ysh.studio.spring.aop.service.UserService.save(User)) Use time : 2 ms!INFO [spring.aop.aspect.ServiceAspect:48] after execution(void cn.ysh.studio.spring.aop.service.UserService.save(User))INFO [spring.aop.aspect.ServiceAspect:74] afterReturn execution(void cn.ysh.studio.spring.aop.service.UserService.save(User))INFO [spring.aop.aspect.ServiceAspect:40] before execution(boolean cn.ysh.studio.spring.aop.service.UserService.delete(long))INFO [spring.aop.service.UserService:32] delete method . . .INFO [spring.aop.aspect.ServiceAspect:65] around execution(boolean cn.ysh.studio.spring.aop.service.UserService.delete(long)) Use time : 5 ms with exception : spring aop ThrowAdvice演示INFO [spring.aop.aspect.ServiceAspect:48] after execution(boolean cn.ysh.studio.spring.aop.service.UserService.delete(long))INFO [spring.aop.aspect.ServiceAspect:74] afterReturn execution(boolean cn.ysh.studio.spring.aop.service.UserService.delete(long))WARN [studio.spring.aop.Tester:32] Delete user : Null return value from advice does not match primitive return type for: public boolean cn.ysh.studio.spring.aop.service.UserService.delete(long) throws java.lang.Exception
可以看到,正如我们预期的那样,虽然我们并没有对UserSerivce类包括其调用方式做任何改变,但是Spring仍然拦截到了其中方法的调用,或许这正是AOP的魔力所在。
再简单说一下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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><!– 系统服务组件的切面Bean –><bean id="serviceAspect" class="cn.ysh.studio.spring.aop.aspect.ServiceAspect"/><!– AOP配置 –><aop:config><!– 声明一个切面,并注入切面Bean,相当于@Aspect –><aop:aspect id="simpleAspect" ref="serviceAspect"><!– 配置一个切入点,相当于@Pointcut –><aop:pointcut expression="execution(* cn.ysh.studio.spring.aop.service..*(..))" id="simplePointcut"/><!– 配置通知,相当于@Before、@After、@AfterReturn、@Around、@AfterThrowing –><aop:before pointcut-ref="simplePointcut" method="before"/><aop:after pointcut-ref="simplePointcut" method="after"/><aop:after-returning pointcut-ref="simplePointcut" method="afterReturn"/><aop:after-throwing pointcut-ref="simplePointcut" method="afterThrow" throwing="ex"/></aop:aspect></aop:config></beans>
个人觉得不如注解灵活和强大,你可以不同意这个观点,但是不知道如下的代码会不会让你的想法有所改善:
//配置前置通知,拦截返回值为cn.ysh.studio.spring.mvc.bean.User的方法@Before("execution(cn.ysh.studio.spring.mvc.bean.User cn.ysh.studio.spring.aop.service..*(..))")public void beforeReturnUser(JoinPoint joinPoint){if(log.isInfoEnabled()){log.info("beforeReturnUser " + joinPoint);}}//配置前置通知,拦截参数为cn.ysh.studio.spring.mvc.bean.User的方法@Before("execution(* cn.ysh.studio.spring.aop.service..*(cn.ysh.studio.spring.mvc.bean.User))")public void beforeArgUser(JoinPoint joinPoint){if(log.isInfoEnabled()){log.info("beforeArgUser " + joinPoint);}}//配置前置通知,拦截含有long类型参数的方法,并将参数值注入到当前方法的形参id中@Before("aspect()&&args(id)")public void beforeArgId(JoinPoint joinPoint, long id){if(log.isInfoEnabled()){log.info("beforeArgId " + joinPoint + " ID:" + id);}}
附上UserService的代码(其实很简单):
package cn.ysh.studio.spring.aop.service;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import cn.ysh.studio.spring.mvc.bean.User;/*** 用户服务模型* @author Shenghany* @date 2013-5-28*/public class UserService {private final static Log log = LogFactory.getLog(UserService.class);public User get(long id){if(log.isInfoEnabled()){log.info("getUser method . . .");}return new User();}public void save(User user){if(log.isInfoEnabled()){log.info("saveUser method . . .");}}public boolean delete(long id) throws Exception{if(log.isInfoEnabled()){log.info("delete method . . .");throw new Exception("spring aop ThrowAdvice演示");}return false;}}
应该说学习Spring AOP有两个难点,第一点在于理解AOP的理念和相关概念,第二点在于灵活掌握和使用切入点表达式。概念的理解通常不在一朝一夕,慢慢浸泡的时间长了,自然就明白了,下面我们简单地介绍一下切入点表达式的配置规则吧。
通常情况下,表达式中使用”execution“就可以满足大部分的要求。表达式格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
modifiers-pattern:方法的操作权限
ret-type-pattern:返回值
declaring-type-pattern:方法所在的包
name-pattern:方法名
parm-pattern:参数名
throws-pattern:异常
其中,除ret-type-pattern和name-pattern之外,其他都是可选的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值为任意类型;方法名任意;参数不作限制的所有方法。
最后说一下通知参数
可以通过args来绑定参数,这样就可以在通知(Advice)中访问具体参数了。例如,<aop:aspect>配置如下:
<aop:config><aop:aspect id="TestAspect" ref="aspectBean"><aop:pointcut id="businessService"expression="execution(* com.spring.service.*.*(String,..)) and args(msg,..)" /><aop:after pointcut-ref="businessService" method="doAfter"/></aop:aspect></aop:config>上面的代码args(msg,..)是指将切入点方法上的第一个String类型参数添加到参数名为msg的通知的入参上,这样就可以直接使用该参数啦。
H. spring mvc aop注解切入点
不太明白你的意思。spring AOP有2种方法来实现切入点。1。用@注解方式 直接开启事务(用起来比较方便)2。用默认配置文件方式(。xml))(正规大项目 都采用第二种方法,因为这样统一,还可观)希望对你有所帮助