打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Spring面向切面
1.AspectJ - AOP

面向切面编程是面向对象的一个补充

在保存用户前添加一个日志,再加上时刻的记录。 总之,就是方法前后加一点业务逻辑

新建资源库:Preference>Java>BuildPath>UserLibraries,AddLibrary>UserLibrary

/Spring_AOP/src/yuki/spring/aop/imitate/UserService.java

package yuki.spring.aop.imitate;public interface UserService {    void save();}

/Spring_AOP/src/yuki/spring/aop/imitate/UserServiceImpl.java

package yuki.spring.aop.imitate;public class UserServiceImpl implements UserService{    public void save(){        System.out.println("user saved...");    }}

/Spring_AOP/src/yuki/spring/aop/imitate/Intercepter.java

package yuki.spring.aop.imitate;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public abstract class Intercepter implements InvocationHandler {  private Object target;  public void setTarget(Object target) {    this.target = target;  }    protected abstract void beforeMethod();  protected abstract void afterMethod();    @Override  public Object invoke(Object proxy, Method m, Object[] args)      throws Throwable {    beforeMethod();    m.invoke(target, args);    afterMethod();    return null;  }}

/Spring_AOP/src/yuki/spring/aop/imitate/LogIntercepter.java

package yuki.spring.aop.imitate;public class LogIntercepter extends Intercepter {  @Override  public void beforeMethod() {    System.out.println("log start...");  }  @Override  protected void afterMethod() {    System.out.println("log end...");  }}

/Spring_AOP/src/yuki/spring/aop/imitate/TimeIntercepter.java

package yuki.spring.aop.imitate;public class TimeIntercepter extends Intercepter {  @Override  protected void beforeMethod() {    System.out.println("start:" + System.currentTimeMillis());  }  @Override  protected void afterMethod() {    System.out.println("end:" + System.currentTimeMillis());  }}

/Spring_AOP/src/yuki/spring/aop/imitate/ProxyTest.java

package yuki.spring.aop.imitate;import java.lang.reflect.Proxy;public class ProxyTest {  public static void main(String[] args) {    UserService service = new UserServiceImpl();        Intercepter[] intercepters = {new LogIntercepter(), new TimeIntercepter()};    for(Intercepter intercepter : intercepters){      intercepter.setTarget(service);      service = (UserService) Proxy.newProxyInstance(          service.getClass().getClassLoader(),           service.getClass().getInterfaces(), intercepter);    }        service.save();      }}

上面的程序中,两个类继承了实现InvocationHandler接口的抽象类,

也可以说是间接地实现了InvocationHandler接口;

声明为UserService接口类型的service,

在循环中每一次接收Proxy.newProxyInstance方法的计算结果后就会改变它指向的对象。

运行结果如下:

start:1409496143248log start...user saved...log end...end:1409496143250

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

注解的方式实现AOP使用的是aspectj,

aspectj是专门用来产生动态代理的一个框架

可以使用aspectj注解的方式实现spring的AOP,

把这个逻辑织入到原来的逻辑里面去

引入jar:aspectjrt.jar、aspectj-weaver.jar:http://www.java2s.com/Code/Jar/a/aspectj.htm

在类上添加注解 @Aspect和 @Component,在方法上添加注解 @Before

切入点语法 @Before("execution(public void yuki.spring.aop.annotation"

+ ".UserServiceImpl.save(yuki.spring.aop.annotation.User))")

引入jar:aopalliance-.jar:

http://www.java2s.com/Code/Jar/a/Downloadaopalliancejar.htm

@Component要加在对应的实现类上,因为getBean后要获取这个对象

/Spring_AOP/src/yuki/spring/aop/annotation/User.java

package yuki.spring.aop.annotation;public class User {}

/Spring_AOP/src/yuki/spring/aop/annotation/UserService.java

package yuki.spring.aop.annotation;public interface UserService {    void save(User user);}

/Spring_AOP/src/yuki/spring/aop/annotation/UserServiceImpl.java

package yuki.spring.aop.annotation;import org.springframework.stereotype.Component;@Component("userService")public class UserServiceImpl implements UserService{    public void save(User user){        System.out.println("user saved...");    }}

/Spring_AOP/src/annotation.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:context="http://www.springframework.org/schema/context"     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.0.xsd       http://www.springframework.org/schema/aop       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-4.0.xsd ">        <context:annotation-config></context:annotation-config>    <context:component-scan base-package="yuki.spring.aop.annotation"></context:component-scan>        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>    </beans>

/Spring_AOP/src/yuki/spring/aop/annotation/LogIntercepter.java

package yuki.spring.aop.annotation;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;@Aspect@Componentpublic class LogIntercepter {    @Before("execution(public void yuki.spring.aop.annotation"            + ".UserServiceImpl.save(yuki.spring.aop.annotation.User))")    public void beforeMethod() {        System.out.println("method start...");    }}

/Spring_AOP/src/yuki/spring/aop/annotation/TimeIntercepter.java

package yuki.spring.aop.annotation;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;@Aspect@Componentpublic class TimeIntercepter {  @Before("execution("      + "public * yuki.spring.aop.annotation..*.*(..)"      + ")")  public void beforeMethod() {    System.out.println("before:" + System.currentTimeMillis());  }  @AfterReturning("execution( public * yuki.spring.aop.annotation..*.*(..) )")  public void afterReturningMethod() {    System.out.println("afterReturning:" + System.currentTimeMillis());  }}

/Spring_AOP/src/yuki/spring/aop/annotation/PointcutIntercepter.java

package yuki.spring.aop.annotation;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;@Aspect@Componentpublic class PointcutIntercepter {  @Pointcut("execution( public * yuki.spring.aop.annotation..*.*(..) )")  public void myMethod() {}    @Before("myMethod()")  public void beforeMethod() {    System.out.println("PointcutIntercepter::before");  }  @AfterReturning("myMethod()")  public void afterReturningMethod() {    System.out.println("PointcutIntercepter::afterReturning");  }}

/Spring_AOP/src/yuki/spring/aop/annotation/UserServiceTest.java

package yuki.spring.aop.annotation;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserServiceTest {  @Test  public void testSave() {        @SuppressWarnings("resource")    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("annotation.xml");    UserService service = (UserService) context.getBean("userService");    service.save(new User());    context.destroy();  }}

运行结果如下:

八月 31, 2014 10:59:10 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 22:59:10 CST 2014]; root of context hierarchy八月 31, 2014 10:59:10 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [annotation.xml]method start...PointcutIntercepter::beforebefore:1409497152268user saved...afterReturning:1409497152268PointcutIntercepter::afterReturning八月 31, 2014 10:59:12 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 22:59:10 CST 2014]; root of context hierarchy

术语解释:

JoinPoint:连接点、切入点,在哪里把逻辑加进区

PointCut:JoinPoint的集合,可以一次性定义好多切入点

Aspect:切面,切面类加进去的逻辑可以认为是一个切面

Advice:在这个点上建议怎么办,比如 @Before

Target:被织入逻辑的被代理对象

Weave:织入

2.切面和通知

切入点:

// the execution of any public method:

execution(public * *(..))

// the execution of any method with a name beginning with "set":

execution(* set*(..))

// the execution of any method defined by the AccountService interface:

execution(* com.xyz.service.AccountService.*(..))

// the execution of any method defined in the service package:

execution(* com.xyz.service..(..))

// the execution of any method defined in the service package or a sub-package:

execution(* com.xyz.service..*.*(..))

spring也定义了自己的织入点语法,但是我们只要用AspectJ的语法就可以了

通知:

Before、AfterReturn、AfterThrowing、After(意思是finally)

Around:在ProceedingJoinPoint.proceed()前后加逻辑

如果织入点表达式相同,可以定义Pointcut

定义方法名接收织入点表达式的值,使用时 @AfterReturning("pointcut()")

/Spring_AOP/src/yuki/spring/aop/pointcut/User.java

package yuki.spring.aop.pointcut;public class User {}

/Spring_AOP/src/yuki/spring/aop/pointcut/UserService.java

package yuki.spring.aop.pointcut;public interface UserService {    void save(User user);}

/Spring_AOP/src/yuki/spring/aop/pointcut/UserServiceImpl.java

package yuki.spring.aop.pointcut;import org.springframework.stereotype.Component;@Component("userService")public class UserServiceImpl implements UserService{    public void save(User user){        System.out.println("user saved...");        //throw new RuntimeException("exception...");    }}

/Spring_AOP/src/yuki/spring/aop/pointcut/TransactionAspect.java

package yuki.spring.aop.pointcut;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.AfterReturning;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;import org.springframework.stereotype.Component;@Aspect@Componentpublic class TransactionAspect {  @Pointcut("execution( public * yuki.spring.aop.pointcut..*.*(..) )")  public void pointcut(){}    @Before("pointcut()")  public void before(){    System.out.println("before");  }  @AfterReturning("pointcut()")  public void afterReturning(){    System.out.println("afterReturning");  }  @AfterThrowing("pointcut()")  public void afterThrowing(){    System.out.println("afterThrowing");  }    @Around("pointcut()")  public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable{    System.out.println("method around start...");    pjp.proceed();    System.out.println("method around end...");  }  }

/Spring_AOP/src/pointcut.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:context="http://www.springframework.org/schema/context"     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.0.xsd       http://www.springframework.org/schema/aop       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-4.0.xsd ">        <context:annotation-config></context:annotation-config>    <context:component-scan base-package="yuki.spring.aop.pointcut"></context:component-scan>        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>    </beans>

/Spring_AOP/src/yuki/spring/aop/pointcut/UserServiceTest.java

package yuki.spring.aop.pointcut;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserServiceTest {  @Test  public void testSave() {        @SuppressWarnings("resource")    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("pointcut.xml");    UserService service = (UserService) context.getBean("userService");    service.save(new User());    context.destroy();  }}

运行结果如下:

八月 31, 2014 11:09:22 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:09:22 CST 2014]; root of context hierarchy八月 31, 2014 11:09:22 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [pointcut.xml]method around start...beforeuser saved...method around end...afterReturning八月 31, 2014 11:09:24 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:09:22 CST 2014]; root of context hierarchy

可以实现声明式的异常管理,

struts2已经实现了声明式的异常管理,

这里略过通知执行的先后顺序

3.cglib

如果被代理的类实现了接口, 

就会使用JDK自带的Proxy和InvocationHandler来实现代理

当被代理的类没有实现接口, 

它会用cglib直接操作二进制码的形式来产生代理的代码

引入jar:cglib-2.2.jar:http://www.java2s.com/Code/Jar/c/Downloadcglib22jar.htm

/Spring_AOP/src/yuki/spring/aop/cglib/UserService.java

package yuki.spring.aop.cglib;import org.springframework.stereotype.Component;@Componentpublic class UserService {    public void save(){        System.out.println("user saved...");    }}

/Spring_AOP/src/yuki/spring/aop/cglib/CglibAspect.java

package yuki.spring.aop.cglib;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect@Componentpublic class CglibAspect {  @Pointcut("execution( public * yuki.spring.aop.cglib..*.*(..) )")  public void pointcut(){}    @Around("pointcut()")  public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable{    System.out.println("method around start...");    pjp.proceed();    System.out.println("method around end...");  }  }

/Spring_AOP/src/cglib.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:context="http://www.springframework.org/schema/context"     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.0.xsd       http://www.springframework.org/schema/aop       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-4.0.xsd ">        <context:annotation-config></context:annotation-config>    <context:component-scan base-package="yuki.spring.aop.cglib"></context:component-scan>        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>    </beans>

/Spring_AOP/src/yuki/spring/aop/cglib/UserServiceTest.java

package yuki.spring.aop.cglib;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserServiceTest {  @Test  public void testSave() {        @SuppressWarnings("resource")    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("cglib.xml");    UserService service = (UserService) context.getBean("userService");    System.out.println(service.getClass());    service.save();    context.destroy();  }}

运行结果如下:

八月 31, 2014 11:14:17 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:14:17 CST 2014]; root of context hierarchy八月 31, 2014 11:14:17 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [cglib.xml]class yuki.spring.aop.cglib.UserService$$EnhancerBySpringCGLIB$$b8ea6837method around start...user saved...method around end...八月 31, 2014 11:14:19 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:14:17 CST 2014]; root of context hierarchy

4.xml:AOP

pointcut可以声明在aspect的里面或外面

eclipse:从源码视图切换到设计视图

在执行UserService.save()时,发现符合配置的切入点表达式

对应的是LogAspect.before(),于是先执行before,然后save()

可以直接指定pointcut,也可以在外部指定然后再引用它

如果使用第三方类的切面类逻辑,那么就必须要使用xml配置的方式

/Spring_AOP/src/yuki/spring/aop/xml/UserService.java

package yuki.spring.aop.xml;import org.springframework.stereotype.Component;@Component("userService")public class UserService {    public void save(){        System.out.println("user saved...");    }}

/Spring_AOP/src/yuki/spring/aop/xml/LogAspect.java

package yuki.spring.aop.xml;public class LogAspect {    public void before() {        System.out.println("method start...");    }}

/Spring_AOP/src/xml.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:context="http://www.springframework.org/schema/context"     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.0.xsd       http://www.springframework.org/schema/aop       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd       http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-4.0.xsd ">        <context:annotation-config></context:annotation-config>    <context:component-scan base-package="yuki.spring.aop.xml"></context:component-scan>        <bean id="logAspect" class="yuki.spring.aop.xml.LogAspect"></bean>    <!--     <aop:config>        <aop:pointcut id="servicePointcut"                expression="execution( public * yuki.spring.aop.xml..*.*(..) )" />        <aop:aspect id="logAspect" ref="logAspect">            <aop:before method="before" pointcut-ref="servicePointcut"/>        </aop:aspect>    </aop:config>     -->    <aop:config>        <aop:aspect id="logAspect" ref="logAspect">            <aop:before method="before"   pointcut="execution( public * yuki.spring.aop.xml..*.*(..) )"/>        </aop:aspect>    </aop:config></beans>

/Spring_AOP/src/yuki/spring/aop/xml/UserServiceTest.java

package yuki.spring.aop.xml;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserServiceTest {  @Test  public void testSave() {        @SuppressWarnings("resource")    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("xml.xml");    UserService service = (UserService) context.getBean("userService");    service.save();    context.destroy();  }}

运行结果如下:

八月 31, 2014 11:19:01 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:19:01 CST 2014]; root of context hierarchy八月 31, 2014 11:19:01 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [xml.xml]method start...user saved...八月 31, 2014 11:19:02 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:19:01 CST 2014]; root of context hierarchy

5.tomcat debug的热部署

在tomcat的jdk虚拟机参数中添加

-Dcom.sun.management.jmxremote=true

如果修改配置文件,使用了自定义标签的jsp页面,修改了注解,等等情况:还是要重启服务器的

在方法内部修改代码,不用重启服务器,这已经是很大的便捷了,

有兴趣的小伙伴们去研究功能更强大的热部署吧。。。。

目录结构:

本文参考了[尚学堂马士兵_Spring_AOP]的公开课程

更多好文请关注:http://www.cnblogs.com/kodoyang/

>*_*<

kongdongyang

2014/8/31

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
知识点七:Spring AOP技术
Spring学习手札(二)面向切面编程AOP
Spring AOP 常用的四种实现方式 - Spring之旅 - JavaEye技术社区
AOP之基于AspectJ注解总结与案例
Spring AOP示例(注解方式)
Spring AOP原理及拦截器
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服