- BeanPostProcessor接口的使用
BeanPostProcessor接口用在bean生成后将放入ApplicationContext前进行一些必要的处理,它有两个方法,分别在调用bean配置的init-method前后执行(如果配置了的话),本接口的实现类常常结合动态代理生成bean的代理类型:
class MyProxyClass {
private Object target;
public MyProxyClass(Object target) {
this.target = target;
}
public Object getNewProxy() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("you can do something here!!");
Object obj = method.invoke(target, args);
System.out.println("you can do something here!!");
return obj;
}
});
}
}
接口使用如下,接口使用如下,一般只要在postProcessAfterInitialization里面配置后即可(事实上这在实际开发中很少使用,一般会使用spring提供的组件,但其底层是使用这些的)
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String id)
throws BeansException {
//参数Object 为生成的bean id 为该bean在配置文件中的id,这里我们一该用动态代理来生成一个代理对象返回
return new MyProxyClass(bean).getNewProxy();
}
public Object postProcessBeforeInitialization(Object bean, String id)
throws BeansException {
return bean;
}
}
配置如下:
<bean id="myprocessor" class="edu.yzu.filter.MyBeanPostProcessor" />
如上配置后spring 会自动为每个生成的bean生成相应的代理,如上代理的的效果为在调用每个方法找对应此bean的id,,,我们可以使用动态代理来生成
- 对bean中方法的方法的拦截(既自定义的Advice)共有四种,分别为四个接口,继承此四个接口后分别实现对应的方法:
MethodBeforeAdvice(在方法调用之前)
public void before(Method method, Object[] args, Object target)
throws Throwable {
//要在方法调用之前执行的操作
}
MethodInterceptor (在方法调用之前之后都可以用此接口中的一个方法得到)
AfterReturningAdvice(在方法返回以后)
public void afterReturning(Object returnValue, Method method, Object[] args,
Object targer) throws Throwable {
//在方法调用之后 要执行的操作
}
ThrowsAdvice(在方法抛出异常以后会拦截)
public void afterThrowing(Exception e) {
Session session=HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.getTransaction().rollback();
}
注意:ThrowsAdvice接口中没有任何方法,但是使用此接口必须给出的方法签名为:afterThrowing,它可以重载多次,当相应的异常发生后调用对应的处理方法
使用:在配置文件中配置自定义的Advice,比如我有一个 TranstionManager类,它用来控制事务,实现了MethodInterceptor,如下!
public class TranstionManager implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
Session session = HibernateSessionFactory.getSessionFactory()
.getCurrentSession();
Transaction trans = session.getTransaction();
trans.begin();
Object obj = invocation.proceed();
trans.commit();
return obj;
}
}
文件的配置如下:
<bean id="transtionmanager" class="edu.yzu.filter.TranstionManager"/>
另外有一个bean即为拦截的目标对象,为其生成代理对象,该bean的配置如下:
<bean id="userDao" class="edu.yzu.dao.impl.UserDaoImpl"/>
<bean id="userBiz" class="edu.yzu.biz.impl.UserBizImpl">
<property name="userDao">
<ref local="userDao"/>//将userDao注入到到UserBizImpl中
</property>
</bean>
下面为userBiz生成代理对象的bean使用时用ApplicationContext对象实例applicationContext调用代理对象的方法为:applicationContext.getBean(“userBizImpl”);
<bean id="userBizImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="userBiz"/>//指定给哪个目标对象建立代理
</property>
<property name="interceptorNames">
<list>
<value>transtionmanager</value>
//使用的Advice, 可以配置多个
</list>
</property>
<property name="interfaces">
<list>
<value>edu.yzu.biz.UserBiz</value>
//指定要代理目标对象的哪个的接口
</list>
</property>
</bean>
(上面是为实现接口的类生成代理) 缺点:一旦为一个bean指定代理,则bean中的所有方法都会被代理,不能指定为特定的方法指定代理,没有体现面向切面的特点!优点,依然可以拿到代理前的bean对象。如果没有实现任何接口,则不必要加name=”interfaces” 的项,但要加<property name="proxyTargetClass">
<value>true</value>
</property>表示这个bean没有实现任何接口,spring为它生成它的子类(cglib实现)
- 切面=切入点+切入内容。既为:aspect=pointcut+advice spring 中切面用advisor表示,可以在配置文件中配置。切入的内容即为我们自定义的类型,它实现四个接口的的任何一个。切入点即为要切入内容的目标类型的方法:由此可知切面的配置也要配置这两项!
l 为一个bean配置一个advisor ,一个advisor里面只能有一个advice,但是可以给此advisor指定几个切入点,方法如下:
<bean id="myadvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref local="transtionmanager"/>
</property>
<property name="mappedNames">
<list>
<value>addProduct</value>
<value>deleteProductById</value>
<value>getAllProducts</value>
<value>getProduct</value>
<value>getProducts</value>
<value>updateProduct</value>
</list>
</property>
</bean>
这个Advisor只指定的advice为transtionmanager 为切入的内容,切入点为list只的几个方法名,既所代理的bean中,只有方法名相同的才能被切入。这正是面向切面的思想所在,advisor用法如下:
<bean id="productBizImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="productBiz"/>
</property>
<property name="interceptorNames">
<list>
<value>myadvisor</value>
<value>exceptionadvice</value>//这个是没有包装的advice,配置如下:
//<bean id="exceptionadvice" class="edu.yzu.filter.ExceptionFilter"/>
</list>
</property>
<property name="interfaces">
<list>
<value>edu.yzu.biz.ProductBiz</value>
</list>
</property>
</bean>
这样做的好处体现了面向切面的思想,既给指定的切入点切入想要执行的内容。
下面是为多个bean指定多个advisor的方法,似乎也是最为常用的。
l 第一种:为多个bean同时指定多个advisor
Advisor配置不变,如下
<bean id="myadvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref local="transtionmanager"/>
</property>
<property name="mappedNames">
<list>
<value>addProduct</value>
<value>deleteProductById</value>
<value>getAllProducts</value>
<value>getProduct</value>
<value>getProducts</value>
<value>updateProduct</value>
</list>
</property>
</bean>
指定代理的目标对象的配置如下,既为哪些目标bean生成代理
<bean id="autoProxy"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>myadvisor</value>
<value>exceptionadvisor</value>
//自定义的advisor
</list>
</property>
<property name="beanNames">
<list>
<value>userBiz</value>
<value>productBiz</value>
//生成代理的目标对象
</list>
</property>
</bean>
优点:可以同时为多个bean指定多个advisor。不足,因为是自动的为指定的bean生成代理,所以不能再得到原来的bean,只能拿到代理后的bean对象
l 第二种:为多个bean同时指定多个advisor
完整配置如下:
<bean id="userBiz" class="edu.yzu.biz.impl.UserBizImpl">
<property name="userDao">
<bean id="userDao" class="edu.yzu.dao.impl.UserDaoImpl" />
</property>
</bean>
<bean id="productBiz" class="edu.yzu.biz.impl.ProductBizImpl">
<property name="productDao">
<bean id="productDao" class="edu.yzu.dao.impl.ProductDaoImpl" />
</property>
</bean>
<bean id="myadvisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<bean id="transtionmanager" class="edu.yzu.filter.TranstionManager" />
</property>
<property name="mappedNames">
<list>
<value>addProduct</value>
<value>deleteProductById</value>
<value>getAllProducts</value>
<value>getProduct</value>
<value>getProducts</value>
<value>updateProduct</value>
</list>
</property>
</bean>
<bean id="exceptionadvice"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<bean id="exadvice" class="edu.yzu.filter.ExceptionFilter" />
</property>
<property name="mappedNames">
<list>
<value>addProduct</value>
<value>deleteProductById</value>
<value>getAllProducts</value>
<value>getProduct</value>
<value>getProducts</value>
<value>updateProduct</value>
</list>
</property>
</bean>
<bean id="defaultautoproxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
优点,可以同时多个bean指定多个,advisor,缺点:可控性差。会为整个配置文件的所有的非advisor的bean都指定所有的advisor。注意事项,不必要的bean不要放在一个配置文件中,或者放在另外一个bean的内部,但是这样的bean对外界不可见,即不可用ApplicationContext的对象通过getBean得到!(实际用得不多)
声明式的事务管理(Declarative transaction management):
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>oracle.jdbc.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@localhost:1521:XE</value>
</property>
<property name="username">
<value>rose</value>
</property>
<property name="password">
<value>aier</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.Oracle9Dialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">15</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>com/kettas/shops/entity/Entity.hbm.xml</value>
</list>
</property>
</bean>
<bean id="hibernatetemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<!--
dao的bean
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-->
<bean id="userDao" class="edu.yzu.shops.dao.impl.UserDaoImpl">
<property name="hibernateTemplate">
<ref local="hibernatetemplate" />
</property>
</bean>
<!--
biz的配置
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-->
<bean id="userBiz" class="edu.yzu.shops.biz.impl.UserBizImpl">
<property name="userDao">
<ref local="userDao" />
</property>
</bean>
<!--
事物控制
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="update*">
PROPAGATION_REQUIRED,-Exception
</prop>
<prop key="delete*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<!-- 有两种方式可以给一个bean加上事务控制,一种为自动创建。
另一种是指明创建 .第一种为:-->
<bean id="autoProxy"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>userBiz</value>
<value>productBiz</value>
<value>orderBiz</value>
<value>orderItemBiz</value>
<value>categoryBiz</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<!-- 第二种方法为下面,显然表比较少时用第二种可以,但是当表比较多时显然第一种更合适。 -->
<bean id="userBizProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target">
<ref bean="userBiz" />
</property>
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<!-- 下面的设置表时要代理的不是类本身,而是其实现的接口 -->
<property name="proxyTargetClass">
<value>false</value>
</property>
<property name="proxyInterfaces">
<list>
<value>edu.yzu.biz.UserBiz</value>
</list>
</property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="update*">
PROPAGATION_REQUIRED,-Exception
</prop>
<prop key="delete*">
PROPAGATION_REQUIRED,-Exception
</prop>
</props>
</property>
</bean>
<!--
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-->
1.
2.
3.
4.
5.
6.
7. <bean
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置事务管理器 -->
<property>
<ref bean="transactionManager" />
</property>
<!-- 此属性指定目标类本身是否是代理的对象,如果目标类没有实现任何类,就设为true代表自己 -->
<property>
<value>false</value>
</property>
<property>
<value> com.test.service.userManageService</value>
</property>
<!-- 目标bean -->
<property>
<ref bean="userManageService"/>
</property>
<!-- 配置事务属性 -->
<property>
<props>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
利用继承的思想简化配置,适合相对比较多的模块时使用。
<bean id="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<!-- 配置事务管理器 -->
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
8.<bean
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<!-- 配置事务管理器 -->
<property>
<ref bean="transactionManager" />
</property>
<!-- 配置事务属性 -->
<property>
<props>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
而具体的模块可以简单的这样配置。只要指明它的parent(父类)就可以了。父类一般把abstract="true",因为在容器加载的时候不需要初始化,等到用的时候再有它的子类调用的时候,再去初始化。
Java代码
<bean id="userManageServiceProxy" parent="transactionBase" >
<property name="target">
<ref bean="userBiz"/>
</property>
</bean> <bean parent="transactionBase" >
<property>
<ref bean="userManageService"/>
</property>
</bean>
- 文件的配置。在web.xml中配置dwr的拦截器,为一个Servlet,配置如下:
<servlet>
<servlet-name>dwrServlet</servlet-name>
<servlet-class>
org.directwebremoting.servlet.DwrServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwrServlet</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
- 在dwr.xml文件中的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
"http://getahead.org/dwr/dwr20.dtd">
<dwr>
<allow>
<create javascript="JTestBean" creator="new">
<param name="class" value="edu.yzu.dwr.TestBean"/>
</create>
<convert converter="bean" match="edu.yzu.dwr.Student"/>
<!--
<convert converter="bean" match="edu.yzu.dwr.Teacher"/>
若是在方法签名或者返回类型中用到了自定义类型,则要加上这一句,即给自定义类型一个转换器,在客户端会自动被转换为js对象 -->
</allow>
<!—下面也有必要配置一下,即当所使用的方法签名有用到泛型集合时要指定(往往不配置也没没有什么错误)-- >
<signatures>
<![CDATA[
import java.util.* ;
import edu.yzu.entity.*.*;
public List<User> queryAllUsers() ;
]]>
</signatures>
- 在所使用的页面引用dwr动态生成的js文件!
<script src="/ajax/dwr/interface/JTestBean.js"></script>
<script src="/ajax/dwr/engine.js"></script>
如果有必要还可以引用dwr提供的一个util.js的工具包
- dwr整合spring的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
"http://getahead.org/dwr/dwr20.dtd">
<!-- dwr与spring的整合
create标签的creator值为spring表时dwr在不创建对象,而是使用
spring托管的对象。
它的param标签的name属性为beanName,value属性的值与spring中bean
的id值对应。
-->
<dwr>
<allow>
<create javascript="userBiz" creator="spring">
<param name="beanName" value="userBiz" />
</create>
<convert converter="bean" match="edu.yzu.shops.entity.User" />
</allow>
</dwr>