切面编程,实现切面插入,让代码更加灵活。
1.继承实现
新建一个接口:
public interface UserService { public abstract void syso(); }
来个实现类,
public class ExtendAOP extends UserServiceImpl { /** 通过继承方式实现aop切面插入。 * 缺点:只能单继承。 */ @Override public void syso() { System.out.println("开始切入"); super.syso(); System.out.println("切入完毕"); } }
测试:
@org.junit.Test public void test(){ ExtendAOP aop=new ExtendAOP(); aop.syso(); }
结果:
开始切入
打印日志
切入完毕
2.静态代理模式,接口加多一个方法。
public interface UserService { public abstract void print(); public void syso(); }
实现:
public class Proxy implements UserService { /** * 静态代理,通过实现接口的方式,但是同样要创建实例,没有动态代理。 */ UserServiceImpl userServiceImpl = new UserServiceImpl(); @Override public void print() { } @Override public void syso() { System.out.println("开始切入"); userServiceImpl.syso(); System.out.println("切入完毕"); } }
测试:
@org.junit.Test public void proxy(){ Proxy proxy=new Proxy(); proxy.syso(); }
结果:
开始切入
打印日志
切入完毕
3.使用sping框架提供的aop插入功能,使用配置文件配置。
jar包
同样还是接口和接口的实现。…
配置文件加上
<!-- AOP配置文件写法 --> <bean id="logger" class="logger.Logger"></bean> <aop:config> <aop:pointcut expression="execution (* service.impl.User*.*(..))" id="aop"/><!-- 返回值 service.impl包下任意java,任意方法 参数随意 --> <aop:aspect ref="logger"> <aop:before method="before" pointcut-ref="aop"/> <aop:after method="after" pointcut-ref="aop"/> <aop:around method="logAround" pointcut-ref="aop"/> <aop:after-returning method="afterReturning" pointcut-ref="aop"/> </aop:aspect> </aop:config>
其中bean 对应着相应的插入的类路径 ,aop:point 表示插入点,后面的表达式匹配要插入的地方。 aop:aspect插入面,对应着插入类,下面就是各个对应的方法该插入到那里。(注:这里是关键的配置,其他的没加上来。单元测试还要有获得对象的bean或者注解扫描包的配置。)
插入的实现类:Logger
public class Logger { public static void print(){ System.out.println("打印日志"); } public static void before(){ System.out.println("-----before------"); } public static void after(){ System.out.println("-----after------"); } /** 环绕 通知 */ public Object logAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("---前--环绕日志--------"); Object ret = pjp.proceed();// 执行目标方法相当于InvocationHandler System.out.println("---后--环绕日志--------"); return ret; } public static void afterReturning(){ System.out.println("-----after-returning------"); } }
测试:
@org.junit.Test public void Aop(){ ApplicationContext context=new ClassPathXmlApplicationContext("application4.xml"); UserService service= (UserService) context.getBean("userServiceImpl"); service.syso(); }
结果:(xml注释after、logAround、afterReturning)
-----before------
打印日志
4.用AOP注解了实现。
插入实现类:
@Aspect @Component public class LoggerByAnnotation { @Pointcut("execution(* service.impl.UserService2Impl.*(..))") private void anyMethod(){} @Before("anyMethod()
") public static void before(){ System.out.println("-----before------"); } @After("anyMethod()
") public static void after(){ System.out.println("-----after------"); } /** 环绕 通知 */ @Around("anyMethod()
") public Object logAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("----前--环绕日志--------"); Object ret = pjp.proceed();// 执行目标方法相当于InvocationHandler System.out.println("----后--环绕日志--------"); return ret; } @AfterReturning("anyMethod()
") public static void afterReturning(){ System.out.println("-----after-returning------"); } public static void print() { System.out.println("gggggg"); } }
配置文件:
<!-- Aop注解的方式 --> <!-- AOP插入的类也要扫描一波 --> <context:component-scan base-package="logger"></context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"></aop:aspectj-autoproxy> <!-- CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多, 所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法, 对于final方法,无法进行代理 -->
注意:pring中的切面类固然要用@Aspect标注,但也不要忘了用@Componet标注,这样才能被注册到容器中。
测试:
@org.junit.Test public void Aop(){ ApplicationContext context=new ClassPathXmlApplicationContext("application4.xml"); UserService2 service= (UserService2) context.getBean("userService2Impl"); service.save(); }
结果:
-----before------
打印日志