package c4_aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
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;
/*
* 1,在软件开发中,散布于应用中多处的功能被称为横切关注点,通常来讲,这些横切关注点从
* 概念上是与应用的业务逻辑相分离的。但是我们往往会直接嵌入到应用的业务逻辑之中,把这
* 些横切关注点与业务逻辑相分离正是面向切面编程(AOP)所要解决的问题。
*
* 2,我们使用依赖注入(DI)管理和配置对象。DI有助于应用对象之间的解耦,而AOP可以实现横
* 切关注点与他们所影响的对象之间的解耦。
*
* 3,描述切面的术语有通知(advice),切点(pointcut)和连接点(joinpoint)
*
* 4,通知:在AOP术语中,切面的工作定义为通知。通知定义了切面是什么以及何时使用,还解
* 决了何时执行这个工作的问题
* Spring切面可以应用5中类型的通知:
* 前置通知(Before):在目标方法被调用之前调用通知功能
* 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么
* 返回通知(After-returning):在目标方法成功执行之后调用通知
* 异常通知(After-throwing):在目标方法抛出异常后调用通知
* 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定
* 义的行为
*
* 5,切点:如果说通知定义了切面的什么和何时的话,name切点就定义了何处
*
* 6,切面:切面是通知和切点的结合。通知和切点共同定义了切面的全部内容--他是什么,在何时
* 和何处完成其功能
*
* 7,织入:织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织
* 入目标对象中。在目标对象的生命周期里有多个点可以进行织入:
* 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就
* 是以这种方式织入切面的
* 类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),
* 它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving,LTW)就支持以这种方式织入切面。
* 运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目
* 标对象动态的创建一个代理对象。Spring AOP就是以这种方式织入切面的。
*
* 通知包含了需要用于多个应用对象的横切行为,连接点是程序执行过程中能够应用通知的所
* 有点,切点定义了通知被应用的具体位置(在哪些连接点)。其中关键的概念是切点定义了哪
* 些连接点会得到通知。
*
* 8,Spring对AOP的支持
* Spring提供了4中类型的AOP支持:
* 基于代理的经典Spring AOP
* 纯POJO切面
* @AspectJ注解驱动的切面
* 注入式AspectJ切面(使用于Spring各版本)
*
* 前3种都是Spring AOP的变体,Spring AOP构建在动态代理基础之上,因此,Spring对AOP
* 的支持局限于方法拦截。
*
* 9,Spring在运行时通知对象
* 通过在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中。
* 代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。当代理
* 拦截到方法调用时,在调用目标bean方法之前,会执行切面逻辑。
*
*
*/
@Aspect
public class Audience {
// execution:在方法执行前触发
// **:返回任意类型
// *:方法所属的任意类
// perform:方法
// & : and,且
// !bean('woodstock'):任意id不为woodstock的bean
@Pointcut(value = "execution(** *.perform(..)) && !bean('woodstock')")
public void performance() {}
@Before("performance()")
public void silenceCellPhone() {
System.out.println("表演之前 silencing cellPhone");
}
@After("performance()")
public void afterPerformance() {
System.out.println("表演之后 after performance");
}
@AfterThrowing("performance()")
public void demanRefund() {
System.out.println("表演异常 demanding a refund");
}
// 环绕通知
@Around("performance()")
public void watchPerformance(ProceedingJoinPoint joinPoint) {
try {
System.out.println("around before performance...");
joinPoint.proceed();
System.out.println("around after performance...");
}catch(Throwable t) {
t.printStackTrace();
}
}
}
package c4_aop;
public interface Performance {
void perform();
}
package c4_aop;
public class Singer implements Performance{
@Override
public void perform() {
System.out.println("i am a singer, i am singing a song");
}
}
package c4_aop;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = {"c4_aop"})
//启动AspectJ自动代理
@EnableAspectJAutoProxy
public class PerformanceConfig {
@Bean("performance")
public Performance performance() {
return new Singer();
}
@Bean
public Audience audience() {
return new Audience();
}
}
package c4_aop;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= {PerformanceConfig.class})
public class AOPTest {
@Autowired
private Performance performance;
@Test
public void testAop() {
performance.perform();
}
}
XML配置:
AOP pointcut传参:如记录某一首歌唱了多少次
package c4_aop;
import java.util.ArrayList;
import java.util.List;
public class Singer implements Performance{
private List songs = new ArrayList<>();
@Override
public void perform() {
System.out.println("i am a singer, i am singing a song ");
}
@Override
public void sing(String name) {
System.out.println("i am singing : " + name);
}
public List getSongs() {
return songs;
}
public void setSongs(List songs) {
this.songs = songs;
}
}
package c4_aop;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class SongCounter {
private Map songCounts = new HashMap<>();
@Pointcut("execution(** *.sing(java.lang.String)) && args(songName)")
public void singerSing(String songName) {}
@Before("singerSing(songName)")
public void countSong(String songName) {
songCounts.put(songName, getSongCount(songName) + 1);
}
public Integer getSongCount(String songName) {
return songCounts.containsKey(songName) ? songCounts.get(songName) : 0;
}
}
package c4_aop;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class SongCounterConfig {
@Bean("performance")
public Performance performance() {
return new Singer();
}
@Bean("songCounter")
public SongCounter songCounter() {
return new SongCounter();
}
}
package c4_aop;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= {SongCounterConfig.class})
public class AOPTest {
@Autowired
private Performance performance;
@Autowired
private SongCounter songCounter;
@Test
public void testAspectWithArgs() {
performance.sing("千里之外");
performance.sing("听妈妈的话");
performance.sing("龙战骑士");
performance.sing("千里之外");
performance.sing("七里香");
performance.sing("听妈妈的话");
performance.sing("菊花台");
performance.sing("千里之外");
System.out.println("千里之外:" + songCounter.getSongCount("千里之外"));
System.out.println("听妈妈的话:" + songCounter.getSongCount("听妈妈的话"));
System.out.println("龙战骑士:" + songCounter.getSongCount("龙战骑士"));
System.out.println("菊花台:" + songCounter.getSongCount("菊花台"));
System.out.println("七里香:" + songCounter.getSongCount("七里香"));
}
/*@Test
public void testAop() {
performance.perform();
}*/
}
通过注解为类引入新功能:
为Performance的所有子类添加一个shout方法
package c4_aop;
public interface Performance {
void perform();
void sing(String name);
}
package c4_aop;
import java.util.ArrayList;
import java.util.List;
public class Singer implements Performance{
private List songs = new ArrayList<>();
@Override
public void perform() {
System.out.println("i am a singer, i am singing a song ");
}
@Override
public void sing(String name) {
System.out.println("i am singing : " + name);
}
public List getSongs() {
return songs;
}
public void setSongs(List songs) {
this.songs = songs;
}
}
package c4_aop;
public interface Animal {
void shout();
}
package c4_aop;
public class Dog implements Animal{
@Override
public void shout() {
System.out.println("wang wang wang...");
}
}
package c4_aop;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class ExtendFuctionConfig {
@Bean
public Performance performance() {
return new Singer();
}
@Bean
public ExtendFuction extendFuction() {
return new ExtendFuction();
}
@Bean
public Animal animal() {
return new Dog();
}
}
package c4_aop;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= {ExtendFuctionConfig.class})
public class ExtendFunctionTest {
@Autowired
private Performance performance;
@Test
public void test() {
Animal animal = (Animal)performance;
animal.shout();
}
}