接下来进入Spring的另一核心AOP(aspect oriented programming)
面向切面编程, 通过预编译的方式在运行期通过动态代理实现的一种技术, AOP是OOP的延续, 利用AOP可以实现业务和切面的逻辑分离. 降低耦合度, 程序的重用性提高.
1 JDK动态代理
JDK动态代理的目标是接口实现类的形式
直接上代码:
代理类:
package com.rl.spring.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
private Object targetObj;
/**
* 第一个参数: 获得目标对象的类的加载器
* 第二个参数: 获得目标对象的接口
* 第三个参数: 设置回调对象, 当前代理对象(也就是UserServiceImpl)的方法(save方法)被调用时, 会委派该参数去调用invoke
需要传入InvocationHandler的子类, 这里用this指代JDKProxy
* @return
*/
public Object createProxyInstance(Object targetObj) {
this.targetObj = targetObj;
return Proxy.newProxyInstance(this.targetObj.getClass().getClassLoader(),
this.targetObj.getClass().getInterfaces(), this);
}
/**
* proxy: 代理类
* Method: 要调用的业务方法
* Object[]: 调用的业务方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获得目标对象的get方法
Method getMeth = this.targetObj.getClass().getMethod("getUser", null);
// 通过反射来调用getUser
Object user = getMeth.invoke(targetObj, null);
Object obj = null;
if (user != null) {
// 业务方法返回的值
obj = method.invoke(this.targetObj, args);
} else {
System.out.println("您还没有登录");
}
return obj;
}
}
测试类:
package com.rl.spring.test;
import org.junit.Test;
import com.rl.spring.model.User;
import com.rl.spring.proxy.JDKProxy;
import com.rl.spring.service.UserService;
import com.rl.spring.service.impl.UserServiceImpl;
public class TestSpring {
@Test
public void Test() {
UserServiceImpl ui = new UserServiceImpl();
ui.setUser(new User());
//通过业务接口来接收代理对象
UserService userService = (UserService) new JDKProxy().createProxyInstance(ui);
System.out.println(userService.getClass());
userService.save();
}
}
UserServiceImpl类
package com.rl.spring.service.impl;
import com.rl.spring.model.User;
import com.rl.spring.service.UserService;
public class UserServiceImpl implements UserService {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public void save() {
System.out.println("保存用户...");
}
@Override
public void update() {
System.out.println("修改用户...");
}
}
输出:
保存用户.../ 如果在测试代码中没有new User()的话, 则提示"您还没有登录!"
小总结:
代理类提供了一种切面针对目标对象的一种拦截并做相应处理, 在User类中并没有逻辑处理, 但却能够实现一种拦截判断是否有登录的效果, 这就是代理类的功能所在.
2 CGLIB动态代理
CGLIB可以对普通类做动态代理, 前提是目标类不能为final, 类里面的方法也不能为final
直接上代码:
代理类:
package com.rl.spring.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class CGLIBProxy implements MethodInterceptor {
private Object targetObj;
public Object createProxyInstance(Object targetObj) {
this.targetObj = targetObj;
Enhancer en = new Enhancer();
en.setSuperclass(this.targetObj.getClass());
en.setCallback(this);
return en.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
Method getMeth = this.targetObj.getClass().getMethod("getUser", null);
Object user = getMeth.invoke(targetObj, null);
Object obj = null;
if(user != null) {
obj = method.invoke(this.targetObj, arg2);
}else {
System.out.println("您还没有登录!");
}
return obj;
}
}
测试代码:
package com.rl.spring.test;
import org.junit.Test;
import com.rl.spring.model.User;
import com.rl.spring.proxy.CGLIBProxy;
import com.rl.spring.proxy.JDKProxy;
import com.rl.spring.service.UserService;
import com.rl.spring.service.impl.UserServiceImpl;
public class TestSpring {
@Test
public void Test1() {
UserServiceImpl ui = new UserServiceImpl();
ui.setUser(new User());
UserServiceImpl userServiceImpl = (UserServiceImpl) new CGLIBProxy().createProxyInstance(ui);
System.out.println(userServiceImpl.getClass());
userServiceImpl.save();
}
}
目标对象(UserServiceImpl同上, 不列出来了), 该类可作为实现类, 也可作为普通类 CGLIB都可以对其做动态代理