工程如图:
pom文件内容:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>com.springinaction</groupId> <artifactId>springidol-aop</artifactId> <version>3.0.0</version> <packaging>jar</packaging> <name>Spring in Action Spring Idol - AOP</name> <url>http://www.manning.com/walls4</url> <properties> <spring.group>org.springframework</spring.group> <spring.version>3.1.1.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>${spring.group}</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>${spring.group}</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>${spring.group}</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>${spring.group}</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.6</version> <scope>test</scope> </dependency> </dependencies> </project>
spring-idol.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="eddie" class="com.springinaction.springidol.Instrumentalist"> <property name="instrument"> <bean class="com.springinaction.springidol.Guitar" /> </property> </bean> <!--<start id="audience_bean" /> --> <bean id="audience" class="com.springinaction.springidol.Audience" /> <!--<end id="audience_bean" /> --> <!--<start id="audience_aspect" /> --> <aop:config> <aop:aspect ref="audience"><!--<co id="co_refAudienceBean"/> --> <aop:before pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="takeSeats" /> <!--<co id="co_beforePointcut"/> --> <aop:before pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="turnOffCellPhones" /> <!--<co id="co_beforePointcut2"/> --> <aop:after-returning pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="applaud" /> <!--<co id="co_afterPointcut"/> --> <aop:after-throwing pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="demandRefund" /> <!--<co id="co_afterThrowingPointcut"/> --> </aop:aspect> </aop:config> <!--<end id="audience_aspect" /> --> </beans>
package com.springinaction.springidol; public interface Instrument { public void play(); }
package com.springinaction.springidol; public interface Performer { void perform() throws PerformanceException; }
package com.springinaction.springidol; public class Guitar implements Instrument { public void play() { System.out.println("Strum strum strum"); } }
package com.springinaction.springidol; public class Instrumentalist implements Performer { public void perform() throws PerformanceException { instrument.play(); } private Instrument instrument; public void setInstrument(Instrument instrument) { this.instrument = instrument; } public Instrument getInstrument() { return instrument; } }
package com.springinaction.springidol; public class Audience { public void takeSeats() { System.out.println("The audience is taking their seats."); } public void turnOffCellPhones() { System.out.println("The audience is turning off their cellphones"); } public void applaud() { System.out.println("CLAP CLAP CLAP CLAP CLAP"); } public void demandRefund() { System.out.println("Boo! We want our money back!"); } }
测试类:
package com.springinaction.springidol; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.springinaction.springidol.Performer; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("spring-idol.xml") public class TestSpringIdol { @Autowired ApplicationContext context; @Test public void audienceShouldApplaud() throws Exception { Performer eddie = (Performer) context.getBean("eddie"); eddie.perform(); } }
2014-4-19 12:32:42 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners 信息: @TestExecutionListeners is not present for class [class com.springinaction.springidol.TestSpringIdol]: using defaults. 2014-4-19 12:32:43 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [com/springinaction/springidol/spring-idol.xml] 2014-4-19 12:32:43 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.GenericApplicationContext@111a3ac: startup date [Sat Apr 19 12:32:43 CST 2014]; root of context hierarchy 2014-4-19 12:32:43 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@23e5d1: defining beans [eddie,audience,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,org.springframework.aop.aspectj.AspectJPointcutAdvisor#1,org.springframework.aop.aspectj.AspectJPointcutAdvisor#2,org.springframework.aop.aspectj.AspectJPointcutAdvisor#3,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy The audience is taking their seats. The audience is turning off their cellphones Strum strum strum CLAP CLAP CLAP CLAP CLAP
AroundAudience:
package com.springinaction.springidol; import org.aspectj.lang.ProceedingJoinPoint; public class AroundAudience { public void watchPerformance(ProceedingJoinPoint joinpoint) { try { System.out.println("The audience is taking their seats."); System.out.println("The audience is turning off their cellphones"); long start = System.currentTimeMillis(); joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("CLAP CLAP CLAP CLAP CLAP"); System.out.println("The performance took " + (end - start) + " milliseconds."); } catch (Throwable t) { System.out.println("Boo! We want our money back!"); } } }
<?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="eddie" class="com.springinaction.springidol.Instrumentalist"> <property name="instrument"> <bean class="com.springinaction.springidol.Guitar" /> </property> </bean> <!-- <start id="audience_bean" /> --> <bean id="audience" class="com.springinaction.springidol.AroundAudience" /> <!-- <end id="audience_bean" /> --> <!-- <start id="audience_aspect" /> --> <aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance" expression="execution(* com.springinaction.springidol.Performer.perform(..))" /> <aop:around pointcut-ref="performance" method="watchPerformance" /> </aop:aspect> </aop:config> <!-- <end id="audience_aspect" /> --> </beans>
package com.springinaction.springidol; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("spring-idol-around.xml") public class TestSpringIdolAround { @Autowired ApplicationContext context; @Test public void audienceShouldApplaud() throws Exception { Performer eddie = (Performer) context.getBean("eddie"); eddie.perform(); } }
2014-4-19 12:40:12 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners 信息: @TestExecutionListeners is not present for class [class com.springinaction.springidol.TestSpringIdolAround]: using defaults. 2014-4-19 12:40:13 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [com/springinaction/springidol/spring-idol-around.xml] 2014-4-19 12:40:13 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.GenericApplicationContext@dd20f6: startup date [Sat Apr 19 12:40:13 CST 2014]; root of context hierarchy 2014-4-19 12:40:13 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@177b3cd: defining beans [eddie,audience,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,performance,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy The audience is taking their seats. The audience is turning off their cellphones Strum strum strum CLAP CLAP CLAP CLAP CLAP The performance took 0 milliseconds.
spring-idol-2.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="eddie" class="com.springinaction.springidol.Instrumentalist"> <property name="instrument"> <bean class="com.springinaction.springidol.Guitar" /> </property> </bean> <!--<start id="audience_bean" /> --> <bean id="audience" class="com.springinaction.springidol.AroundAudience2" /> <!--<end id="audience_bean" /> --> <!--<start id="audience_aspect" /> --> <aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance" expression="execution(* com.springinaction.springidol.Performer.perform(..))" /> <!--<co id="co_defPointcut"/> --> <aop:before pointcut-ref="performance" method="takeSeats" /> <!--<co id="co_refPointcut"/> --> <aop:before pointcut-ref="performance" method="turnOffCellPhones" /> <!--<co id="co_refPointcut"/> --> <aop:after-returning pointcut-ref="performance" method="applaud" /> <!--<co id="co_refPointcut"/> --> <aop:after-throwing pointcut-ref="performance" method="demandRefund" /> <!--<co id="co_refPointcut"/> --> </aop:aspect> </aop:config> <!--<end id="audience_aspect" /> --> <!--<start id="audience_around_advice" /> --> <aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance2" expression="execution(* com.springinaction.springidol.Performer.perform(..))" /> <aop:around pointcut-ref="performance2" method="watchPerformance" /> <!--<co id="co_around"/> --> </aop:aspect> </aop:config> <!--<end id="audience_around_advice" /> --> </beans>
AroundAudience2:
package com.springinaction.springidol; import org.aspectj.lang.ProceedingJoinPoint; public class AroundAudience2 extends Audience { public void watchPerformance(ProceedingJoinPoint joinpoint) { try { long start = System.currentTimeMillis(); joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("The performance took " + (end - start) + " milliseconds."); } catch (Throwable t) { System.out.println("Boo! We want our money back!"); } } }
测试类:
package com.springinaction.springidol; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.springinaction.springidol.Performer; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("spring-idol-2.xml") public class TestSpringIdol2 { @Autowired ApplicationContext context; @Test public void audienceShouldApplaud() throws Exception { Performer eddie = (Performer) context.getBean("eddie"); eddie.perform(); } }
2014-4-19 12:51:47 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners 信息: @TestExecutionListeners is not present for class [class com.springinaction.springidol.TestSpringIdol2]: using defaults. 2014-4-19 12:51:47 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [com/springinaction/springidol/spring-idol-2.xml] 2014-4-19 12:51:47 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.GenericApplicationContext@b89838: startup date [Sat Apr 19 12:51:47 CST 2014]; root of context hierarchy 2014-4-19 12:51:47 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c4fe76: defining beans [eddie,audience,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,org.springframework.aop.aspectj.AspectJPointcutAdvisor#1,org.springframework.aop.aspectj.AspectJPointcutAdvisor#2,org.springframework.aop.aspectj.AspectJPointcutAdvisor#3,performance,org.springframework.aop.aspectj.AspectJPointcutAdvisor#4,performance2,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy The audience is taking their seats. The audience is turning off their cellphones Strum strum strum The performance took 0 milliseconds. CLAP CLAP CLAP CLAP CLAP
sneaky-magician.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="volunteer" class="com.springinaction.springidol.Volunteer" /> <bean id="magician" class="com.springinaction.springidol.Magician" /> <!--<start id="mindreading_aspect"/> --> <aop:config> <aop:aspect ref="magician"> <aop:pointcut id="thinking" expression="execution(* com.springinaction.springidol.Thinker.thinkOfSomething(String)) and args(thoughts)" /> <aop:before pointcut-ref="thinking" method="interceptThoughts" arg-names="thoughts" /> </aop:aspect> </aop:config> <!--<end id="mindreading_aspect"/> --> </beans>
package com.springinaction.springidol; public interface Thinker { void thinkOfSomething(String thoughts); }
package com.springinaction.springidol; public class Volunteer implements Thinker { private String thoughts; public void thinkOfSomething(String thoughts) { this.thoughts = thoughts; } public String getThoughts() { return thoughts; } }
package com.springinaction.springidol; public interface MindReader { void interceptThoughts(String thoughts); String getThoughts(); }
package com.springinaction.springidol; public class Magician implements MindReader { private String thoughts; public void interceptThoughts(String thoughts) { System.out.println("Intercepting volunteer's thoughts"); this.thoughts = thoughts; } public String getThoughts() { return thoughts; } }
package com.springinaction.springidol; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("sneaky-magician.xml") public class TestSneakyMagician { @Autowired ApplicationContext context; @Autowired Thinker thinker; @Autowired MindReader mindReader; @Test public void audienceShouldApplaud() throws Exception { String thoughts = "this is spring aop"; thinker.thinkOfSomething(thoughts); System.out.println(mindReader.getThoughts()); } }
2014-4-19 13:08:43 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners 信息: @TestExecutionListeners is not present for class [class com.springinaction.springidol.TestSneakyMagician]: using defaults. 2014-4-19 13:08:43 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [com/springinaction/springidol/sneaky-magician.xml] 2014-4-19 13:08:43 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.GenericApplicationContext@b89838: startup date [Sat Apr 19 13:08:43 CST 2014]; root of context hierarchy 2014-4-19 13:08:44 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1a99561: defining beans [volunteer,magician,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,thinking,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy Intercepting volunteer's thoughts this is spring aop
spring-idol-introductions.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="eddie" class="com.springinaction.springidol.Instrumentalist"> <property name="instrument"> <bean class="com.springinaction.springidol.Guitar" /> </property> </bean> <!--<start id="audience_bean"/> --> <bean id="audience" class="com.springinaction.springidol.Audience" /> <!--<end id="audience_bean"/> --> <!--<start id="audience_aspect"/> --> <aop:config> <aop:aspect ref="audience"> <aop:pointcut id="performance" expression="execution(* com.springinaction.springidol.Performer.perform(..))" /> <aop:before pointcut-ref="performance" method="takeSeats()" /> <aop:before pointcut-ref="performance" method="turnOffCellPhones" /> <aop:after-returning pointcut-ref="performance" method="applaud" /> <aop:after-throwing pointcut-ref="performance" method="demandRefund" /> </aop:aspect> <!--<start id="contestant_introduction"/> --> <aop:aspect> <aop:declare-parents types-matching="com.springinaction.springidol.Performer+" implement-interface="com.springinaction.springidol.Contestant" default-impl="com.springinaction.springidol.GraciousContestant" /> </aop:aspect> <!--<end id="contestant_introduction"/> --> <!-- <start id="delegate_ref"/> <aop:declare-parents types-matching="com.springinaction.springidol.Performer+" implement-interface="com.springinaction.springidol.Contestant" delegate-ref="contestantDelegate" /> <end id="delegate_ref"/> <start id="contestant_delegate"/> <bean id="contestantDelegate" class="com.springinaction.springidol.GraciousContestant" /> <end id="contestant_delegate"/> --> </aop:config> <!--<end id="audience_aspect" /> --> </beans>
package com.springinaction.springidol; public interface Contestant { void receiveAward(); }
package com.springinaction.springidol; public class GraciousContestant implements Contestant { public void receiveAward() { System.out.println("Why, thank you all very much!"); } }
package com.springinaction.springidol; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("spring-idol-introductions.xml") public class TestSpringIdolIntroductions { @Autowired ApplicationContext context; @Autowired Performer performer; Contestant contestant; @Test public void audienceShouldApplaud() throws Exception { performer.perform(); contestant = (Contestant) performer; contestant.receiveAward(); } }
2014-4-19 13:18:47 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners 信息: @TestExecutionListeners is not present for class [class com.springinaction.springidol.TestSpringIdolIntroductions]: using defaults. 2014-4-19 13:18:47 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [com/springinaction/springidol/spring-idol-introductions.xml] 2014-4-19 13:18:47 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.GenericApplicationContext@b89838: startup date [Sat Apr 19 13:18:47 CST 2014]; root of context hierarchy 2014-4-19 13:18:47 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@b8c8e6: defining beans [eddie,audience,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,org.springframework.aop.aspectj.AspectJPointcutAdvisor#1,org.springframework.aop.aspectj.AspectJPointcutAdvisor#2,org.springframework.aop.aspectj.AspectJPointcutAdvisor#3,performance,org.springframework.aop.aspectj.DeclareParentsAdvisor#0,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy The audience is taking their seats. The audience is turning off their cellphones Strum strum strum CLAP CLAP CLAP CLAP CLAP Why, thank you all very much!