spring AOP简单入门

AOP(aspect oriented programming)面向切面编程。

大致意思是在方法的执行过程中织入其他要执行的方法。

项目结构图

先介绍一下通过代理的方式实现aop,几个文件和上一篇一样,再贴一遍方便观看

package com.ouc.wkp.model;


public class User {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}
User.java
package com.ouc.wkp.dao;

import com.ouc.wkp.model.User;

public interface UserDAO {
    public void save(User user);
    public void delete();
}
UserDAO.java
package com.ouc.wkp.dao.impl;

import org.springframework.stereotype.Component;

import com.ouc.wkp.dao.UserDAO;
import com.ouc.wkp.model.User;

@Component("u")
public class UserDAOImpl implements UserDAO {

    @Override
    public void save(User user) {
        // Hibernate
        // JDBC
        // XML
        // NetWork
        System.out.println("user saved!");
//        throw new RuntimeException();
    }

    @Override
    public void delete() {
        // TODO Auto-generated method stub
        
    }

}
UserDAOImpl.java
package com.ouc.wkp.service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.ouc.wkp.dao.UserDAO;
import com.ouc.wkp.model.User;

@Component("userService")
public class UserService {

    private UserDAO userDAO;

    @PostConstruct
    public void init() {
        System.out.println("init");
    }

    public void add(User user) {
        userDAO.save(user);
    }

    public UserDAO getUserDAO() {
        return userDAO;
    }

    // @Autowired @Qualifier("u")
    @Resource(name = "u")
    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    @PreDestroy
    public void destroy() {
        System.out.println("destroy");
    }
}
UserService.java

然后是一个代理类,继承自InvocationHandler

package com.ouc.wkp.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class LogIntercepter implements InvocationHandler{
    private Object target;

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }
    
    public void beforeMethod(Method m){
        System.out.println(m.getName()+" start");
    }
    
    public void afterMethod(Method m){
        System.out.println(m.getName()+" end");
    }
    
    public Object invoke(Object proxy,Method m,Object[] args) throws Throwable{
        beforeMethod(m);
        m.invoke(target, args);
        afterMethod(m);
        return null;
    }
}
LogIntercepter.java

然后再测试类中进行如下调用

@Test
    public void testProxy() {
        UserDAO userDAO = new UserDAOImpl();
        LogIntercepter li = new LogIntercepter();
        li.setTarget(userDAO); 
        UserDAO userDAOProxy = (UserDAO) Proxy.newProxyInstance(userDAO
                .getClass().getClassLoader(), userDAO.getClass()
                .getInterfaces(), li);
        System.out.println(userDAOProxy.getClass());
        userDAOProxy.delete();
        userDAOProxy.save(new User());
    }
UserServiceTest.java

运行结果

然后介绍通过xml配置文件实现aop

 使用aop需要一下 
 xmlns:aop="http://www.springframework.org/schema/aop" 
 http://www.springframework.org/schema/aop -->
 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 
 <aop:aspectj-autoproxy /> 

还需要这个开启对com.ouc.wkp包下面的扫描

<context:component-scan base-package="com.ouc.wkp"></context:component-scan>

<?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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
    <context:annotation-config />
    <!-- 使用注解需要下面四条 -->
    <!-- xmlns:context="http://www.springframework.org/schema/context" -->
    <!-- http://www.springframework.org/schema/context -->
    <!-- http://www.springframework.org/schema/context/spring-context-3.1.xsd"> -->
    <!-- <context:annotation-config /> -->

    <!-- 使用aop需要一下 -->
    <!-- xmlns:aop="http://www.springframework.org/schema/aop" -->
    <!-- http://www.springframework.org/schema/aop -->
    <!-- http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> -->
    <!-- <aop:aspectj-autoproxy /> -->

    <!-- 扫描 -->
    <context:component-scan base-package="com.ouc.wkp"></context:component-scan>

    <aop:aspectj-autoproxy />

    <bean id="logIntercepter2" class="com.ouc.wkp.aop.LogIntercepter2"></bean>
    <aop:config>
        <!-- <aop:pointcut expression="execution(public * com.ouc.wkp.service..*.add(..))" 
            id="servicePointcut"/> -->
        <!-- <aop:aspect id="logAspect" ref="logIntercepter"> -->
        <!-- <aop:before method="before" pointcut="servicePointcut"/> -->
        <!-- </aop:aspect> -->
        <aop:aspect id="logAspect" ref="logIntercepter2">
            <aop:before method="before"
                pointcut="execution(public * com.ouc.wkp.service..*.add(..))" />
        </aop:aspect>
    </aop:config>
</beans>
beans.xml

<bean id="logIntercepter2" class="com.ouc.wkp.aop.LogIntercepter2"></bean>
<aop:config>
<!-- <aop:pointcut expression="execution(public * com.ouc.wkp.service..*.add(..))"
id="servicePointcut"/> -->
<!-- <aop:aspect id="logAspect" ref="logIntercepter"> -->
<!-- <aop:before method="before" pointcut="servicePointcut"/> -->
<!-- </aop:aspect> -->
<aop:aspect id="logAspect" ref="logIntercepter2">
<aop:before method="before"
pointcut="execution(public * com.ouc.wkp.service..*.add(..))" />
</aop:aspect>
</aop:config>

看下面这段 第一行声明了一个代理切入类(表达不准确)

<aop:pointcut expression="execution(public * com.ouc.wkp.service..*.add(..))" 
id="servicePointcut"/>标识定义一个切入点pointcut。

<aop:before method="before" pointcut="servicePointcut"/>表示before织入这个切入点。

execution(public * com.ouc.wkp.service..*.add(..))代表com.ouc.wkp.service包下的任意包的任意类的add方法。

然后我们看代理切入类

package com.ouc.wkp.aop;

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
@Component
public class LogIntercepter2 {
//    @Pointcut("execution(public * com.ouc.wkp.service..*.add(..))")
    public void myMethod(){};
            
//    @Before("myMethod()")
    public void before() {
        System.out.println("method before");
    }
    
//    @AfterReturning("execution(public * com.ouc.wkp.dao..*.*(..))")
    public void afterReturning(){
        System.out.println("method after returning");
    }
    
//    @AfterThrowing("myMethod()")
    public void afterThrowing(){
        System.out.println("method after throwing");
    }
    
//    @Around("myMethod()")
    public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("method around start");
        pjp.proceed();
        System.out.println("method around end");
    }
}
LogIntercepter2.java

类的开头需要加上

@Aspect
@Component

测试方法

@Test
    public void testAdd() throws Exception {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
                "beans.xml");

        UserService service = (UserService) ctx.getBean("userService");
        User user = new User();
        user.setUsername("qqq");
        user.setPassword("123ppp");
        //是一个代理
        System.out.println(service.getClass());
        service.add(user);

        ctx.destroy();

    }
UserServiceTest.java

运行结果

我们看到我们获得的userservice实质上是一个代理类

最后介绍通过注解实现aop,LogIntercepter2的代码再贴一遍.

beans.xml里面的<aop:config>可以注释掉

package com.ouc.wkp.aop;

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
@Component
public class LogIntercepter2 {
    @Pointcut("execution(public * com.ouc.wkp.service..*.add(..))")
    public void myMethod(){};
            
    @Before("myMethod()")
    public void before() {
        System.out.println("method before");
    }
    
    @AfterReturning("execution(public * com.ouc.wkp.dao..*.*(..))")
    public void afterReturning(){
        System.out.println("method after returning");
    }
    
    @AfterThrowing("myMethod()")
    public void afterThrowing(){
        System.out.println("method after throwing");
    }
    
    @Around("myMethod()")
    public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("method around start");
        pjp.proceed();
        System.out.println("method around end");
    }
}
LogIntercepter2.java

@Pointcut("execution(public * com.ouc.wkp.service..*.add(..))")

public void myMethod(){};表示定义一个切入点

@Before("myMethod()")表示在方法执行前执行注解下面的方法  myMethod()为上面定义的切入点

后面的注解见名知意

运行结果

感觉还是很神奇的 以前一直不理解什么是面向切面。现在简单了解了一下觉得很有趣,但是还是无法用语言准确表达出来= =

下一篇介绍spring整合hibernate

原文地址:https://www.cnblogs.com/wangkaipeng/p/5780422.html