Spring 代理
一.静态代理原理实例:
项目结构:
IUserServ接口代码
[java] view plain copy
public interface IUserServ {
List<User> findAllUser();
int deleteUserById(User user);
int saveUser(User user);
}
UserServImpl实现类代码
[java] view plain copy
public class UserServImpl implements IUserServ {
public int deleteUserById(User user) {
System.out.println("******执行删除方法******");
return 0;
}
public List<User> findAllUser() {
System.out.println("*******执行查询方法*******");
return null;
}
public int saveUser(User user) {
System.out.println("*******执行添加方法********");
return 0;
}
}
UserServProxyImpl实现类代码
[java] view plain copy
//代理类:完成日志输出
public class UserServProxyImpl implements IUserServ {
// 访问目标对象(UserServImpl)
// 代理对象(UserServProxyImpl)
// 创建目标对象
private IUserServ iuserServ ;//= new UserServImpl();
public UserServProxyImpl(IUserServ iuserServ){
this.iuserServ = iuserServ;
}
public int deleteUserById(User user) {
beforeLog();
//调用目标对象里方法
iuserServ.deleteUserById(user);
afterLog();
return 0;
}
public List<User> findAllUser() {
beforeLog();
//调用目标对象里方法
iuserServ.findAllUser();
afterLog();
return null;
}
public int saveUser(User user) {
beforeLog();
//调用目标对象里方法
iuserServ.saveUser(user);
afterLog();
return 0;
}
private void beforeLog() {
System.out.println("开始执行");
}
private void afterLog() {
System.out.println("执行完毕");
}
}
ActionTest测试类代码
[java] view plain copy
public class ActionTest {
public static void main(String[] args) {
//用户访问代理对象---信息->目标对象
IUserServ iuserServ = new UserServProxyImpl(new UserServImpl());
iuserServ.findAllUser();
}
}
运行结果:
开始执行
*执行查询方法*
执行完毕
二.动态代理实例
项目结构图:
IUserServ接口代码与UserServImpl实现类代码和上述代码相同
LogHandler类代码
[java] view plain copy
public class LogHandler implements InvocationHandler {
//目标对象
private Object targetObject;
/**
* 创建动态代理类
* @return object(代理类)
*/
public Object createProxy(Object targetObject){
this.targetObject = targetObject;
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
try {
beforeLog();
//obj: 目标对象--->代理对象的返回值--->返回给调用者的信息
//this.invoke("目标对象","代理对象给目标对象传递参数");
//调用目标对象中方法
obj = method.invoke(targetObject, args);
afterLog();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
//日志管理方法
private void beforeLog(){
System.out.println("开始执行");
}
private void afterLog(){
System.out.println("执行完毕");
}
}
ActionTest测试类代码:
[java] view plain copy
public class ActionTest {
public static void main(String[] args) {
//创建代理对象iuserServ
LogHandler handler = new LogHandler();
IUserServ iuserServ = (IUserServ)handler.createProxy(new UserServImpl());
iuserServ.deleteUserById(new User());
}
}
运行结果:
开始执行
*执行删除方法*
执行完毕
三.Spring AOP使用(2.x版本之前)
项目结构图:
IUserServ接口代码与UserServImpl实现类代码和上述代码相同
配置步骤:
1、配置目标对象(applicationContext.xml)
[html] view plain copy
<bean id="userServTarget" class="com.tarena.biz.impl.UserServImpl"/>
2、配置通知
(a)前置通知(BeforeLogAdvice)
[java] view plain copy
public class BeforeLogAdvice implements MethodBeforeAdvice {
/**
* Method method:调用目标对象的方法
* Object[] args:发送给目标对象的参数列表
* Object target:目标对象
*/
public void before(Method method, Object[] args, Object target)
throws Throwable {
beforeLog();
}
private void beforeLog(){
System.out.println("开始执行");
}
}
(b)后置通知(AfterLogAdvice)
[java] view plain copy
public class AfterLogAdvice implements AfterReturningAdvice {
/**
* Object returnValue:目标对象返回值
* Method method:目标对象方法名
* Object[] args:目标对象参数列表
* Object target:目标对象
*/
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
afterLog();
}
private void afterLog(){
System.out.println("执行完毕");
}
}
(c)在spring容器中,让容器管理通知(applicationContext.xml)
[html] view plain copy
<!-- 定义通知 -->
<!-- 前置通知 -->
<bean id="beforeLogAdvice" class="com.tarena.advice.BeforeLogAdvice"/>
<!-- 后置通知 -->
<bean id="afterLogAdvice" class="com.tarena.advice.AfterLogAdvice"/>
3、配置代理对象(applicationContext.xml)
[html] view plain copy
<!-- 代理类作用: 生成代理类,织入通知 -->
<bean id="userServProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces">
<!-- 可以添加多个接口 -->
<list>
<value>com.tarena.biz.IUserServ</value>
</list>
</property>
<!-- 引入通知 -->
<property name="interceptorNames">
<list>
<value>beforeLogAdvice</value>
<value>afterLogAdvice</value>
</list>
</property>
<!-- 目标对象 -->
<property name="target" ref="userServTarget"/>
</bean>
4.访问()
Spring容器:通过代理对象调用–>织入通知—>目标对象
程序员:访问代理对象
测试类(ActionTest):
[java] view plain copy
public class ActionTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
IUserServ iuserServ = (IUserServ)ac.getBean("userServProxy");
iuserServ.deleteUserById(new User());
iuserServ.findAllUser();
}
}
运行结果:
开始执行
*执行删除方法*
执行完毕
开始执行
*执行查询方法*
执行完毕
四.Spring AOP使用(2.x版本之后)这种方式需要额外添加两个jar包,
存放位置在spring-framework-2.5.6.SEC01\lib\aspectj文件夹下。
项目结构图
IUserServ接口代码与UserServImpl实现类代码和上述代码相同
LogAdvice中
[java] view plain copy
public class LogAdvice {
public void beforeLog(){
System.out.println("开始执行");
}
public void afterLog(){
System.out.println("执行完毕");
}
}
applicationContext.xml中
[html] view plain copy
<!-- spring2.x后 -->
<!-- 目标对象 -->
<bean id="userServImpl" class="com.tarena.biz.impl.UserServImpl"/>
<!-- 通知 -->
<bean id="logAdvice" class="com.tarena.advice.LogAdvice"/>
<aop:config>
<aop:aspect id="logAspect" ref="logAdvice">
<!-- 切入点 -->
<aop:pointcut id="beforePointCut"
expression="execution(* saveUser*(..))"/>
<aop:pointcut id="afterPointCut"
expression="execution(* saveUser*(..))"/>
<!-- 织入(通知作用于切入点) -->
<aop:before method="beforeLog" pointcut-ref="beforePointCut"/>
<aop:after method="afterLog" pointcut-ref="afterPointCut"/>
</aop:aspect>
</aop:config>
测试类:
[java] view plain copy
public class ActionTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
IUserServ iuserServ = (IUserServ)ac.getBean("userServImpl");
iuserServ.deleteUserById(new User());
iuserServ.findAllUser();
iuserServ.saveUser(new User());
}
}
运行结果
*执行删除方法*
*执行查询方法*
开始执行
*执行添加方法**
执行完毕
注:如果要在业务层所有的方法前后添加日志文件,则需要更改为以下配置
[html] view plain copy
<aop:pointcut id="beforePointCut"
expression="execution(* com.tarena.biz.*.*(..))"/>
<aop:pointcut id="afterPointCut"
expression="execution(* com.tarena.biz.*.*(..))"/>
运行结果:
开始执行
*执行删除方法*
执行完毕
开始执行
*执行查询方法*
执行完毕
开始执行
*执行添加方法**
执行完毕