大概在前两章Spring in Action的文章中写了Spring的AOP的简单运用,以及Spring依赖注入DI和Bean的装配各种不同的套路。
一种场景正好温习一下:一个接口多个实现的时候。如下:
1、接口Performance
t;import org.aspectj.lang.annotation.Pointcut;public interface Performance {void perform();
}
2、实现一:PerformanceImpl
t;import org.springframework.stereotype.Component;@Component
public class PerformanceImpl implements Performance {public PerformanceImpl() {}@Overridepublic void perform() {System.out.println("----------执行perform中----------");}
}
3、实现二:Singer
t;import org.springframework.stereotype.Component;@Component
public class Singer implements Performance {@Overridepublic void perform() {System.out.println("---------我是一个演唱家Singer,我正在表演perform----------");}
}
4、JavaConfig自动装配:SpringConfig
t;import t.annotation.Bean;
import t.annotation.ComponentScan;
import t.annotation.Configuration;
import t.annotation.EnableAspectJAutoProxy;@Configuration
@ComponentScan
public class SpringConfig {
}
5、测试用例:Test001
t;import static org.junit.Assert.*;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import st.context.ContextConfiguration;
import st.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=SpringConfig.class)
public class Test001 {@Autowiredprivate Performance pe;@Testpublic void test() {pe.perform();}
}
6、大概会看到这样一个错误:(意思是找到了两个符合要求的匹配项,机器不知道选哪个所以抛出异常了)
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name t.Test001': Unsatisfied dependency expressed through field 'pe': No qualifying bean of type [t.Performance] is defined: expected single matching bean but found 2: performanceImpl,singer;
7、解决方案就是:自己告诉机器指定一个实现类。SpringConfig去掉@ComponentScan注解。然后修改后的如下:
t;import t.annotation.Bean;
import t.annotation.ComponentScan;
import t.annotation.Configuration;
import t.annotation.EnableAspectJAutoProxy;@Configuration
@EnableAspectJAutoProxy
public class SpringConfig {@Beanpublic Performance getPerformance(){return new PerformanceImpl();}
}
8、我这里指定PerformanceImpl。好吧,这都不是重点。这期的重点是AOP切面。
1、写一个日志类:加@Aspect,加@Before("execution(* t.Performance.perform(..))")等:
t;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;@Aspect
public class Log {@Before("execution(* t.Performance.perform(..))")public void beforeLog() {System.out.println("前置日志----beforeLog");}@After("execution(* t.Performance.perform(..))")public void afterLog() {System.out.println("后置日志----afterLog");}
}
2、光写了Log日志类,还只是一个普通的java 对象(POJO)。还需要在配置中生成Log对象,设置自动扫描@EnableAspectJAutoProxy。
t;import t.annotation.Bean;
import t.annotation.ComponentScan;
import t.annotation.Configuration;
import t.annotation.EnableAspectJAutoProxy;@Configuration
@EnableAspectJAutoProxy
public class SpringConfig {@Beanpublic Performance getPerformance(){return new PerformanceImpl();}@Beanpublic Log log(){return new Log(); }
}
3、再次执行测试代码Test001执行结果:
前置日志----beforeLog
----------执行perform中----------
后置日志----afterLog
1.切点是什么?切点t.Performance.perform(..),凡是实现这个接口的实例调用perform方法都会执行。
2.使用切点每次都写一长串,execution(* lconcert.Performance.perform(..))简化如下:
lconcert;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class Log {@Pointcut("execution(* lconcert.Performance.perform(..))")public void perform(){}@Before("perform()")public void beforeLog() {System.out.println("前置日志----beforeLog");}@After("perform()")public void afterLog() {System.out.println("后置日志----afterLog");}
}
3.切面是什么?Log类是切面。
4.如何设置自动代理?当前是通过JavaConfig的方式,对SpringConfig添加了@EnableAspectJAutoProxy,并在容器中生成了切面的Bean(Pojo)。当然也可以通过xml方式配置。xml配置思路同JavaConfig:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""xmlns:xsi=""xmlns:context=""xmlns:aop=""xsi:schemaLocation=" .xsd .3.xsd .3.xsd"><context:component-scan base-package=lconcert"></context:component-scan><aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy><!-- 声明bean --><bean class=lconcert.Log"></bean>
</beans>
然后删除SpringConfig,删除这个因为是通过xml配置,排除干扰。删除Singer,是因为自动扫描,一对多的话还是会报异常。就是最上面说的异常。修改Test001:
lconcert;import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import t.support.ClassPathXmlApplicationContext;public class Test001 {@Autowiredprivate Performance pe;@Testpublic void test() {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/l");pe = Bean(Performance.class);pe.perform();ctx.close();}
}
由于我换了一个lconcert,之前是t,所以替换掉其中的所有。包括Log的切面代码:lconcert;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class Log {@Before("execution(* lconcert.Performance.perform(..))")public void beforeLog() {System.out.println("前置日志----beforeLog");}@After("execution(* lconcert.Performance.perform(..))")public void afterLog() {System.out.println("后置日志----afterLog");}
}
执行结果:
前置日志----beforeLog
----------执行perform中----------
后置日志----afterLog
5、环绕通知:修改Log
lconcert;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class Log {@Pointcut("execution(* lconcert.Performance.perform(..))")public void perform(){}// @Before("perform()")
// public void beforeLog() {
// System.out.println("前置日志----beforeLog");
// }
// @After("perform()")
// public void afterLog() {
// System.out.println("后置日志----afterLog");
// }// 创建环绕通知@Around("perform()")public void watchPerformance(ProceedingJoinPoint jp){try {System.out.println("电话静音,坐下");jp.proceed();} catch (Throwable e) {e.printStackTrace();System.out.println("演出失败,退款");}}}
执行结果:
电话静音,坐下
----------执行perform中----------
其中入参ProceedingJoinPoint,jp.proceed()是执行玩环绕通知后执行perform方法。如果不使用,则不执行perform。perform被拦截了。其中System.out.println("演出失败,退款");是在抛出异常的时候执行。例如null指针异常。
6、处理通知中的参数:
Performance
lconcert;import org.aspectj.lang.annotation.Pointcut;public interface Performance {void perform();void performArgs(int arg);
}
Log
lconcert;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class Log {@Pointcut("execution(* lconcert.Performance.performArgs(int)) && args(num)")public void perform(int num){}@Before("perform(num)")public void beforeLog(int num) {System.out.println("前置日志----beforeLog"+num);}@After("perform(num)")public void afterLog(int num) {System.out.println("后置日志----afterLog"+num);}// 创建环绕通知
// @Around("perform(num)")
// public void watchPerformance(ProceedingJoinPoint jp){
// try {
// System.out.println("电话静音,坐下");
// jp.proceed();
// } catch (Throwable e) {
// e.printStackTrace();
// System.out.println("演出失败,退款");
// }
// }}
Test001
lconcert;import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import t.support.ClassPathXmlApplicationContext;public class Test001 {@Autowiredprivate Performance pe;@Testpublic void test() {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/l");pe = Bean(Performance.class);pe.performArgs(100001);ctx.close();}
}
执行结果:
前置日志----beforeLog100001
----------执行performArgs中----------100001
后置日志----afterLog100001
Player
package demo;public interface Player {void play(String song,int num);
}
CDPlayer
package demo;import org.springframework.stereotype.Component;@Component
public class CDPlayer implements Player {@Overridepublic void play(String song, int num) {System.out.println("歌曲名:"+song+" 播放次数:"+num);}
}
AopLog
package demo;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class AopLog {//计数器private int numCounter = 0;@Pointcut("execution(* demo.Player.play(String,int))&&args(song,num)")public void play(String song,int num){}@Before("play(song,num)")public void before(String song,int num){numCounter = numCounter+num;}public void getNum(){System.out.println("CDPlayer共播放"+numCounter+"次");}
}
l
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""xmlns:xsi=""xmlns:context=""xmlns:aop=""xsi:schemaLocation=" .xsd .3.xsd .3.xsd"><context:component-scan base-package="demo"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy><bean class="demo.AopLog"></bean>
</beans>
TestDemo
package demo;import static org.junit.Assert.*;import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import t.support.ClassPathXmlApplicationContext;public class TestDemo {@Autowiredprivate Player p;@Autowiredprivate AopLog a;@Testpublic void test() {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("l");p = Bean(Player.class);p.play("周杰伦的歌", 1);p.play("周杰伦的歌", 2);p.play("周杰伦的歌", 3);p.play("周杰伦的歌", 4);a = Bean(AopLog.class);a.getNum();ctx.close();}
}
执行结果:
歌曲名:周杰伦的歌 播放次数:1
歌曲名:周杰伦的歌 播放次数:2
歌曲名:周杰伦的歌 播放次数:3
歌曲名:周杰伦的歌 播放次数:4
播放10次
Performer
package newfunc;public interface Performer {void play();
}
MisZhang
package newfunc;import org.springframework.stereotype.Component;@Component
public class MisZhang implements Performer {@Overridepublic void play() {//张女士是表演者System.out.println("唱青藏高原");}}
l
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""xmlns:xsi=""xmlns:context=""xmlns:aop=""xsi:schemaLocation=" .xsd .3.xsd .3.xsd"><bean id="miszhang" class="newfunc.MisZhang"></bean>
</beans>
Test001package newfunc;import static org.junit.Assert.*;import org.junit.Test;
import t.support.ClassPathXmlApplicationContext;public class Test001 {private Performer p;@Testpublic void test() {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("l");p = (Performer) Bean("miszhang");p.play();ctx.close();}}
执行结果:
唱青藏高原需求:现在想对张女士MisZhang.class类,新增一个角色Artister接口。即由原本:张女士是一个唱青藏高原的人-----》升级为:张女士是一个会唱青藏高原的女艺术家。但是不允许对MisZhang.class做任何修改。
Artister
package newfunc;public interface Artister {void honor();
}
DefaultArtister
package newfunc;import org.springframework.stereotype.Component;@Component
public class DefaultArtister implements Artister {@Overridepublic void honor() {System.out.println("--------艺术家光环普照----------");}}
新增切面
EncoreableIntroducer
package newfunc;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;@Aspect
public class EncoreableIntroducer {@DeclareParents(value="newfunc.MisZhang+",defaultImpl=DefaultArtister.class)public static Artister artister;
}
修改l
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""xmlns:xsi=""xmlns:context=""xmlns:aop=""xsi:schemaLocation=" .xsd .3.xsd .3.xsd"><aop:aspectj-autoproxy></aop:aspectj-autoproxy><bean id="miszhang" class="newfunc.MisZhang"></bean><bean class="newfunc.DefaultArtister"></bean><bean class="newfunc.EncoreableIntroducer"></bean>
</beans>
修改Test001
package newfunc;import static org.junit.Assert.*;import org.junit.Test;
import t.support.ClassPathXmlApplicationContext;public class Test001 {private Performer p;private Artister a;@Testpublic void test() {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("l");p = (Performer) Bean("miszhang");p.play();a = (Artister) Bean("miszhang");a.honor();ctx.close();}}
执行结果:
唱青藏高原
--------艺术家光环普照----------
over--------
本文发布于:2024-02-01 03:39:23,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170672996333591.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |