1、简单的spring实现(annotation方式)spring
bean类express
package hello; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class HelloWorld { private String Msg; public void Hello() { System.out.println("Hello:" + Msg); } @Bean(name = "helloworldbean") public HelloWorld helloWorldBean() { HelloWorld hw = new HelloWorld(); hw.Msg = "How are you ?"; return hw; } }
测试类:segmentfault
package hello; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class TestHelloWorld { /** * @param args */ private static ApplicationContext ctx; public static void main(String[] args) { // TODO 自动生成的方法存根 ctx = new AnnotationConfigApplicationContext(HelloWorld.class); HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloworldbean"); helloWorld.Hello(); } }
运行结果:app
2017-10-24 00:34:15 [org.springframework.context.annotation.AnnotationConfigApplicationContext]-[INFO] Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@12bb4df8: startup date [Tue Oct 24 00:34:15 CST 2017]; root of context hierarchy Hello:How are you ?
(xml方式)模块化
bean类函数
package com.hello; public class XmlHello { private String name; public void setName(String name) { this.name = name; } public void printHello() { System.out.println("Spring : Hello ! " + name); } }
xml配置文件applicationContext.xml(放在包com.hello下)测试
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <bean id="helloBean" class="com.hello.XmlHello"> <property name="name" value="Yiibai" /> </bean> </beans>
测试类:this
package com.hello; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AppXmlHello { /** * @param args */ private static ApplicationContext ctx; public static void main(String[] args) { // TODO 自动生成的方法存根 ctx = new ClassPathXmlApplicationContext( "com/hello/applicationContext.xml"); XmlHello helloWorld = (XmlHello) ctx.getBean("helloBean"); helloWorld.printHello();; } }
2、注解方式实现aop(须要导入aspectjrt-1.8.11.jar,aspectjweaver-1.8.11.jar ):spa
package hello; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component @Aspect public class HelloAop { // 声明切点 @Pointcut("execution(* *.Hello())") public void pointcut() { } @Before("pointcut()") public void beforepoint() { System.out.println("接下去调用Hello()......"); } @AfterReturning("pointcut()") public void afterhello() { System.out.println("函数Hello()执行结束......"); } }
bean类HelloWorld(@Configuration后)加上:代理
@ComponentScan @EnableAspectJAutoProxy
TestHelloWorld类不变,运行结果以下 :
2017-11-20 00:23:05 [org.springframework.context.annotation.AnnotationConfigApplicationContext]-[INFO] Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@12bb4df8: startup date [Mon Nov 20 00:23:05 CST 2017]; root of context hierarchy 接下去调用Hello()...... Hello:How are you ? 函数Hello()执行结束......
在软件开发中,散布于应用中多处的功能被称为横切关注点,一般来说,这些横切关注点从概念上是与应用的业务逻辑相分离的。把这些横切关注点和业务逻辑分离出来正是AOP要解决的问题。AOP可以帮咱们模块化横切关注点,换言之,横切关注点能够被描述为影响应用多出的功能。这些横切点被模块化特殊的类,这些类被称为切面。
通知:切面有必需要完成的工做,在AOP中,切面的工做被称为通知。通知定义了切面是什么以及什么时候使用,除了描述切面要完成的工做,通知还解决了什么时候执行这个工做的问题,它应该在某个方法以前?以后?以前和以后都调用?仍是只在方法抛出异常时调用?
链接点:链接点是应用程序执行过程当中,可以插入切面的一个点。
切点:是在链接点的基础上定义切点,比方说一个类由十几个方法,每一个方法的调用前和调用后均可以插入通知,可是你只想选择几个方法插入通知,所以你定义一个切点来选择你想插入的通知的方法。
切面:切面就是通知和切点的结合。
织入:织入是把切面应用到目标对象并建立新的代理对象的过程,切面在指定的链接点被织入到目标对象中。在目标对象的生命周期里有多个点能够进行织入:编译期、类加载期、运行期。其中编译器织入须要特殊的编译器,类加载器织入须要特殊的类加载器,spring的AOP 是在运行期织入通知的。
spring提供了AOP的四种支持,分别是:基于代理的经典Spring AOP模式;纯POJO切面;@AspectJ注解驱动的切面;@注入式AspectJ切面。spring所建立的通知都是用标准的Java类编写的,并且定义通知所应用的切点一般会使用注解或在Spring配置文件里采用XML来编写。
spring只支持方法级别的链接点。
在spring AOP中,要使用AspectJ的切点表达式语言来定义切点,关于Spring AOP的AspectJ切点,最重要的一点就是Spring仅支持AspectJ切点指示器的一个子集:
1.arg() 限制链接点匹配参数为指定类型的执行方法;
2.@args() 限制链接点匹配参数由指定注解标注的执行方法;
3.execution() 用于匹配是链接点的执行方法;
4.this() 限制链接点匹配AOP代理的bean引用为指定类型的类
5.target 限制链接点匹配目标对象为指定类型的类
6.@target() 限制链接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解
7.within() 限制链接点匹配指定的类型
8.@within() 限制链接点匹配特定注解所标注的类型
9.@annotation 限定匹配带有指定注解的链接点
目标对象:
package concert; public interface Performance{ public void perform(); }
切面对象:
package concert; @Aspect//表示Audience的实例是一个切面 public class Audience{ @Before("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法执行以前 } @Before("execution(**concert.Performance.perform(..))") public void takeSeats(){ //在perfrom方法执行以前 } @AfterReturning("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法执行以后 } @AfterThrowing("execution(**concert.Performance.perform(..))") public void silenceCellPhones(){ //在perfrom方法抛出异常以后 } }
上面的类中切点表达式execution(**concert.Performance.perform(..))屡次出现,咱们也能够经过@Pointcut注解避免每次都写很长的切点表可是以下所示:
@Aspect//表示Audience的实例是一个切面 public class Audience{ @Pointcut("execution(**concert.Performance.perform(..))") public void performance(){} @Before("performance()") public void silenceCellPhones(){ //在perfrom方法执行以前 } @Before("performance()") public void takeSeats(){ //在perfrom方法执行以前 } @AfterReturning("performance()") public void silenceCellPhones(){ //在perfrom方法执行以后 } @AfterThrowing("performance()") public void silenceCellPhones(){ //在perfrom方法抛出异常以后 } }
接下来须要在配置文件中配置切面以下所示:
@Configuration @EnableAspectJAutoProxy//启动AspectJ自动代理 @ComponentScan public class ConcertConfig{ } //或者在配置文件中配置中添加 <aop:aspectj-autoproxy /> 表示启动切面代理
环绕通知:
@Aspect//表示Audience的实例是一个切面 public class Audience{ @Pointcut("execution(**concert.Performance.perform(..))") public void performance(){} @Before("performance()") public void watchPerformance(ProceedingJoinPoint jp){ //在方法以前执行 System.out.println(" beform the method is invoked"); jp.proceed()//控制权交给目标方法 //在方法以后执行 System.out.println(" after the method is invoked"); } }
public class Audience{ @Pointcut("execution(**concert.Performance.perform(int))&&args(trackNumber)") public void performance(){} @Before("performance(trackNumber)") public void watchPerformance(int trackNumber){ //截获传递给目标方法的参数并传递给切面中处理方法 System.out.println(trackNumber); } }
spring AOP提供的xml配置元素:
1.<aop:advisor> 定义AOP通知;
2.<aop:after> 后置通知;
3.<aop:after-returning> 返回通知
4.<aop:around> 环绕通知
5.<aop:aspect> 定义一个切面
6.<aop:aspectj-autoproxy> 启用切面注解驱动
7.<aop:before> 前置通知
8.<aop:config> 顶层的AOP配置元素;
9.<aop:pointcut>:定义个切点
<aop:config> <aop:aspect ref="audience"> <aop:before pointcut="execution(**concert.Performance.perform())" method="silenceCellPhones"/> <aop:before pointcut="execution(**concert.Performance.perform())" method="takeSeats"/> <aop:after-returning pointcut="execution(**concert.Performance.perform())" method="applause"/> <aop:after-throwing pointcut="execution(**concert.Performance.perform())" method="demandRefund"/> </aop:aspect> </aop config>
定义切点:
<aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance" expression="execution(**concert.Performance.perform())"> <aop:before pointcut-ref="performance" method="silenceCellPhones"/> <aop:before pointcut="performance" method="takeSeats"/> <aop:after-returning pointcut="performance" method="applause"/> <aop:after-throwing pointcut="performance" method="demandRefund"/> </aop:aspect> </aop config>