Spring AOP + AspectJ framework


AOP(Aspect Orient Programming),也就是常说的面向方面编程,它是作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)

中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。

简单点来说,它就是一个拦截器可以拦截一些进程,例如,当某个方法执行时,Spring AOP 可以拦截该执行的方法,并允许在方法执行之前或之后添加额外的功能,

以上如若解释的不好,勿喷 -_- ||

AspectJ 是一个基于 Java 语言的 AOP 框架,提供了强大的 AOP 功能,Spring 从 2.0 起,对 AspectJ 功能都提供了支持 .

几个常用的 AspectJ 注解 : 

    @Before   在方法执行前被执行

    @After     在方法执行后被执行

    @AfterReturning     在方法执行后被执行,并同时拦截方法返回的结果

    @AfterThrowing      在方法抛出异常时候被执行,若方法不抛出异常,则不会被执行

    @Around   这个,不知道要怎么解释了,比较不好解释,就像你拦截了一个方法,并在适当的时候给予放行,放行前后可以做额外的处理,下面看示例就很容易明白了

环境 :

spring事物配置示例

以前项目中经常用spring,事务处理还没有亲自配置过, 惭愧。现在马上上路.

首先,在spring容器中,配置transactionManager,这个有好多实现,这里以HibernateTransactionManager为例,

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory" />
        </property>
</bean>

然后,再定义一个事务模板

    <bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="transactionManager" />
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="remove*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="incress*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

这个模板怎样应用到业务方法上呢?请看下面的配置

<!-- 
        <bean id="userService" class="com.sclsch.service.impl.UserServiceImpl">
        <property name="userDao">
        <ref bean="BmUserDAO" />
        </property>
        </bean>
    -->
    <!-- 为userService配置事务-->
    <bean id="userService" parent="txProxyTemplate">
        <property name="target">
            <bean class="com.sclsch.service.impl.UserServiceImpl">
                <property name="userDao">
                    <ref bean="BmUserDAO" />
                </property>
            </bean>
        </property>
    </bean>

注释部分是原来没有配置事务的service. parent指定为这个service配置的事务模板.

使用Spring进行Web应用开发(二)使用jdbc的持久层

使用mysql5.0作数据库,运行配置向导,将字符集设为utf-8,将mysql的jdbc driver包mysql-connector-java-3.1.11-bin.jar加入项目的classpath.

我们来完成一个用户User注册功能模块。

domain class: User 如下
package springapp.domain;

/**
* User: Saro
* Date: 2006-4-27
* Time: 9:24:02
*/
public class User implements java.io.Serializable {

private Long id;
private String username;
private String password;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}
//………………………..
//其余field的getter/setter method省略
}

在WEB-INF下建立applicationContext.xml文件,在web.xml中添加如下配置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<!– 于系统启动时,根据contextConfigLocation载入bean配置文件的listener–>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

定义一个业务接口,UserService,代码如下:
package springapp;

import springapp.domain.User;

/**
* User: Saro
* Date: 2006-4-27
*/
public interface UserService {
public void addUser(User user);
public User getUserByUserName(String username);
}

因为其实现依赖dao,创建类UserJdbcDao:

package springapp.dao;

import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import springapp.domain.User;

import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.util.List;

/**
* User: Saro
* Date: 2006-4-27
*/
public class UserJdbcDao extends JdbcDaoSupport {
public final static String INSERT_USER=
“insert into T_User (username,password) values(?,?)”;

public final static String SELECT_USER_BYUSERNAME=
“select id,username,password from T_User where username=?”;

public void save(final User user) {
PreparedStatementCreator psc = new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
PreparedStatement p=con.prepareStatement(UserJdbcDao.INSERT_USER);
p.setString(1,user.getUsername());
p.setString(2,user.getPassword());
return p;
}
};
this.getJdbcTemplate().update(psc);
}

public static class UserRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
User user=new User();
user.setId(new Long(rs.getLong(1)));
user.setUsername(rs.getString(2));
user.setPassword(rs.getString(3));
return user;
}
}

public User getByUsername(String username){
List list=this.getJdbcTemplate().query(UserJdbcDao.SELECT_USER_BYUSERNAME,new String[]{username},new UserJdbcDao.UserRowMapper());
if(list.size()==0){
return null;
}
return (User)list.get(0);
}
}

其在applicationContext.xml中定义如下:
<bean id=”userDao” >
<property name=”dataSource” ref=”dataSource” />
</bean>

UserService的实现类:
package springapp;

import springapp.domain.User;
import springapp.dao.UserJdbcDao;

/**
* User: Saro
* Date: 2006-4-27
*/
public class UserServiceImpl implements UserService {

public void addUser(User user) {
this.userDao.save(user);
}

public User getUserByUserName(String username) {
return this.userDao.getByUsername(username);
}

private UserJdbcDao userDao;

public void setUserDao(UserJdbcDao userDao) {
this.userDao = userDao;
}
}
其在applicationContext.xml中定义如下:
<bean id=”userService” >
<property name=”userDao” ref=”userDao” />
</bean>

为了事务控制,加入如下配置:
没有的事务控制的普通bean。
<bean id=” userServiceTarget” >
<property name=”userDao” ref=”userDao” />
</bean>
Jdbc事务管理器
<bean
id=”txManager”>
<property name=”dataSource” ref=”dataSource”/>
</bean>

事务代理工厂类,用于生产其方法有事务控制的代理bean。
<bean
id=”userService”>
<property name=”transactionManager” ref=”txManager”/>
<property name=”target” ref=”userServiceTarget”/>
<property name=”transactionAttributes”>
<props>
<prop key=”get*”>PROPAGATION_REQUIRED,readOnly</prop>
<prop key=”find*”>PROPAGATION_REQUIRED,readOnly</prop>
<prop key=”*”>PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

最后applicationContext.xml如下:
<?xml version=”1.0″ encoding=”UTF-8″ ?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>

<beans>
<bean
id=”dataSource” destroy-method=”close”>
<property name=”driverClass” value=”com.mysql.jdbc.Driver” />
<property name=”jdbcUrl” value=”jdbc:mysql://localhost:3306/example” />
<property name=”user” value=”root” />
<property name=”password” value=”1″ />
<property name=”initialPoolSize” value=”1″ />
<property name=”minPoolSize” value=”2″ />
<property name=”maxPoolSize” value=”5″ />
<property name=”checkoutTimeout” value=”5000″ />
<property name=”maxIdleTime” value=”1800″ />
<property name=”idleConnectionTestPeriod” value=”3000″ />
<property name=”acquireIncrement” value=”5″ />
</bean>

<bean id=”userDao” >
<property name=”dataSource” ref=”dataSource” />
</bean>
<bean id=”userServiceTarget” >
<property name=”userDao” ref=”userDao” />
</bean>

<bean
id=”txManager”>
<property name=”dataSource” ref=”dataSource”/>
</bean>

<bean
id=”userService”>
<property name=”transactionManager” ref=”txManager”/>
<property name=”target” ref=”userServiceTarget”/>
<property name=”transactionAttributes”>
<props>
<prop key=”get*”>PROPAGATION_REQUIRED,readOnly</prop>
<prop key=”find*”>PROPAGATION_REQUIRED,readOnly</prop>
<prop key=”*”>PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

</beans>
建表T_User:
DROP TABLE IF EXISTS `example`.`t_user`;
CREATE TABLE  `example`.`t_user` (
`id` int(10) unsigned NOT NULL auto_increment,
`username` varchar(45) NOT NULL default ”,
`password` varchar(45) NOT NULL default ”,
PRIMARY KEY  (`id`),
UNIQUE KEY `Index_2` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

现在可以写一个UserSerivce的测试类了,
package springapp;

import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import springapp.domain.User;

/**
* User: Saro
* Date: 2006-4-27
*/
public class UserServiceTest extends TestCase {

private ApplicationContext context;

public Object getBean(String beanName){
if(context==null){
context=new FileSystemXmlApplicationContext(“WEB-INF/applicationContext.xml”);
}
return context.getBean(beanName);
}

public UserService getUserService(){
return (UserService)this.getBean(“userService”);
}

public void testAddUser(){
User user=new User();
user.setUsername(“tester01″);
user.setPassword(“1234″);
this.getUserService().addUser(user);
}

public void findUserByUserName(){
User user=new User();
user.setUsername(“tester02″);
user.setPassword(“1234″);
this.getUserService().addUser(user);
User loadedUser=this.getUserService().getUserByUserName(user.getUsername());
assertNotNull(loadedUser);
}

}

SimpleFormController的生命周期:

Get生命周期

Post的生命周期

运行2个测试,顺利通过,持久层和业务层的代码已经写完。下面我们开始写web层的代码。
首先需要一个用于用户注册的Controller:

package springapp.web;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import springapp.UserService;
import springapp.domain.User;

/**
* User: Saro
* Date: 2006-4-27
*/
public class RegUserController extends SimpleFormController {

protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
//在表单绑定到command对象上时,空的表单字串作null处理
binder.registerCustomEditor(String.class,new StringTrimmerEditor(true));
}

protected ModelAndView onSubmit(Object command) throws Exception {
User user=(User)command;
this.userService.addUser(user);
return new ModelAndView(this.getSuccessView());
}

private UserService userService;

public void setUserService(UserService userService) {
this.userService = userService;
}
}

为用户注册添加一个Validator,禁止输入空的用户名称。
package springapp.web;

import org.springframework.validation.Validator;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import springapp.domain.User;

/**
* User: Saro
* Date: 2006-4-27
*/
public class RegValidator implements Validator {
public boolean supports(Class clazz) {
return clazz.isAssignableFrom(User.class);
}

public void validate(Object obj, Errors errors) {
User user=(User)obj;
// required.username 在classpath根目录下的messages.properties中定义
//第4个参数为默认消息
ValidationUtils.rejectIfEmpty(errors,”username”,”required.username”,”用户名称不能为空”);
}
}

springapp-servlet.xml中的配置:
<?xml version=”1.0″ encoding=”UTF-8″ ?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>

<beans>

<bean
id=”exceptionResolver”>
<property name=”exceptionMappings”>
<props>
<prop key=”org.springframework.dao.DataAccessException”>/dataAccessFailure.jsp</prop>
<prop key=”org.springframework.transaction.TransactionException”>/dataAccessFailure.jsp</prop>
</props>
</property>
</bean>
<bean
id=”messageSource”>
<property name=”basename” value=”messages”/>
</bean>
<bean
id=”urlHandlerMapping”>
<property name=”mappings”>
<value>
index.htm = welcomeController
reg.htm = RegUserController
</value>
</property>
</bean>

<bean id=”welcomeController” />

<bean id=”RegUserController” >
<property name=”commandName” value=”addUser” />
<property name=”commandClass” value=”springapp.domain.User” />
<property name=”formView” value=”/reg.jsp” />
<property name=”successView” value=”/end.jsp” />
<property name=”userService” ref=”userService” />
<property name=”validator” >
<bean />
</property>
</bean>
</beans>

创建jsp文件reg.jsp(用于提交用户注册表单),end.jsp(通用结果显示页面)
reg.jsp如下:
<%–
User: Saro
Date: 2006-4-27
–%>
<%@ page contentType=”text/html;charset=UTF-8″ language=”java” %>
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %>
<%@ taglib prefix=”fmt” uri=”http://java.sun.com/jsp/jstl/fmt” %>
<%@ taglib prefix=”fn” uri=”http://java.sun.com/jsp/jstl/functions” %>
<%@ taglib prefix=”spring” uri=”http://www.springframework.org/tags” %>
<html>
<head><title>用户注册</title></head>
<body>用户注册
<spring:nestedPath path=”addUser” >
<form action=”" method=”post”><spring:bind path=”username” >
用户名:<input type=”text” value=”${status.value}” name=”${status.expression}” /> ${status.errorMessage}<br/>
</spring:bind>
<spring:bind path=”password” >
密码:<input type=”text” value=”${status.value}” name=”${status.expression}” /> ${status.errorMessage}</spring:bind>
<input type=”submit” value=”提交”/>
</form>
</spring:nestedPath>
</body>
</html></spring:bind>
</body>
</html>

运行tomcat,访问网址:http://localhost:8080/reg.htm。

加载spring配置文件的工具类

public class AppContext {

  private static AppContext instance;

  private AbstractApplicationContext appContext;

  public synchronized static AppContext getInstance() {

    if (instance == null) {

      instance = new AppContext();

    }

    return instance;

  }

  private AppContext() {

    this.appContext = new ClassPathXmlApplicationContext(

        "applicationContext.xml");

  }

  public AbstractApplicationContext getAppContext() {

    return appContext;

  }

}

在BaseAction中

public class BaseAction extends Action {

    public BaseAction() {

        super();

    }

    protected IBookService getBookService() {

        return (IBookService) AppContext.getInstance().getAppContext(). getBean(

                "bookService");

    }

    protected IOrderService getOrderService() {

        return (IOrderService) AppContext.getInstance().getAppContext(). getBean(

                "orderService");

    }

    protected ICustomerService getCustomerService() {

        return (ICustomerService) AppContext.getInstance().getAppContext(). getBean(

                "customerService");

    }

    protected IOrderItemService getOrderItemService() {

        return (IOrderItemService) AppContext.getInstance().getAppContext(). getBean(

                "orderItemService");

    }

    protected String checkUser(HttpServletRequest request,

            HttpServletResponse response){

        Customer user = null;

        user = (Customer) request.getSession().getAttribute("user");

        if(user==null){

            System.out.println("you have no loginning!!!!");

            ActionErrors errors = new ActionErrors();

            errors.add(ActionErrors.GLOBAL_MESSAGE,new ActionError("errors. login"));

            this.saveErrors(request,errors);

            return null;

        }else{

            return user.getCustName();

        }
    }

}

spring定时器

<bean id="checkWiner" class="com.daacc.schedule.CheckWiner">
        <property name="mgr">
            <ref local="userServiceTarget"/>
        </property>
    </bean>
    
    <bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
        <property name="delay">
            <value>0</value>
        </property>
        <property name="period">
            <value>10000</value>
        </property>
        <property name="timerTask">
            <ref local="checkWiner"/>
        </property>
    </bean>
        <bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
        <property name="scheduledTimerTasks">
            <list>
                <ref bean="scheduledTask"/>
            </list>
        </property>
    </bean>

spring的aop示例代码

package step6;

public interface IHello {
public void hello(String name);
public void morning(String name);
}

package step6;

public class HelloSpeaker implements IHello {

public void hello(String name) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(“Hello, ” + name);
}

public void morning(String name) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(“Morning, ” + name);
}

}

package step6;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.lang.reflect.*;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodBeforeAdvice;

public class LogBeforeAdvice implements MethodBeforeAdvice {
private Logger logger = Logger.getLogger(this.getClass().getName());

public void before(Method method, Object[] args, Object target)
throws Throwable {
logger.log(Level.INFO, “method starts…” + method);
}
}

package step6;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.lang.reflect.*;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

public class LogAfterAdvice implements AfterReturningAdvice {
private Logger logger = Logger.getLogger(this.getClass().getName());

public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
logger.log(Level.INFO, “method ends…” + method);
}
}

package step6;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import sun.management.FileSystem;

public class Test {
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext(
“/src/step6/bean.xml”);
IHello helloProxy = (IHello) context.getBean(“helloProxy”);
helloProxy.hello(“Justin”);
helloProxy.morning(“monor”);
}
}
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd“>

<beans>
<bean id=”helloProxy”
class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”proxyInterfaces”>
<value>step6.IHello</value>
</property>
<property name=”target”>
<ref bean=”helloSpeaker” />
</property>
<property name=”interceptorNames”>
<list>
<value>logBeforeAdvisor</value>
<value>logAfterAdvisor</value>
</list>
</property>
</bean>
<bean id=”logBeforeAdvisor”
class=”org.springframework.aop.support.RegexpMethodPointcutAdvisor”>
<property name=”advice”>
<ref bean=”logBeforeAdvice” />
</property>
<property name=”patterns”>
<value>step6/.IHello/.morning</value>
</property>
</bean>
<bean id=”logAfterAdvisor”
class=”org.springframework.aop.support.RegexpMethodPointcutAdvisor”>
<property name=”advice”>
<ref bean=”logAfterAdvice” />
</property>
<property name=”patterns”>
<value>step6/.IHello/.hello</value>
</property>
</bean>
<bean id=”helloSpeaker”></bean>
<bean id=”logAfterAdvice”></bean>
<bean id=”logBeforeAdvice”></bean>

</beans>