简介
动态代理是通过指一个代理对象来创建需要的业务对象,然后在这个代理对象中统一进行各种需求的处理;使用动态代理需要如下 4 个步骤:
(1) 创建一个类,实现 InvocationHandler 接口
(2) 创建代理对象
(3) 创建一个方法来生成对象,这个方法的参数是要代理对象
(4) 有了代理对象后,不管这个代理对象执行什么方法,都会调用 Invoke 方法
实现步骤
- 创建实体类 LogProxy.class,实现 InvocationHandler 接口,并添加如下代码
// 1.创建实体类, 实现 InvocationHandler 接口
public class LogProxy implements InvocationHandler { // 2.创建一个代理对象
private Object target;
// 3.创建一个方法生成对象, 该方法的参数就是要代理的对象, 返回值就是被代理的对象
public static Object getInstance(Object object) {
// 3.1 创建 LogProxy 对象
LogProxy proxy = new LogProxy();
// 3.2 设置这个代理对象
proxy.target = object;
// 3.3 通过 Proxy 对象创建代理对象, 第一个参数是要代理对象的 ClassLoader;
// 第二个参数是要代理对象实现的所有接口;
// 第三个参数是实现类 InvocationHandler 的对象
Object result = Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass.getInterfaces(), proxy);
// 此时的 result 就是一个代理对象, 代理的就是 object
return result;
}
// 有了代理对象后,不管这个代理对象执行什么方法, 都会调用下面这个 invoke 方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(new Date() + " ---> 进行了操作: " + method);
Object object = method.invoke(target, args);
return object;
}
}
- 在 beans.xml 中添加如下配置,注册一个 Bean,通过这个代理的 Bean 去代理 UserDao
<!-- 设置代理对象 proxyUserDao, 注意此处 getInstance 是静态方法, userDao 是关联的对象 -->
<bean name="proxyUserDao" class="com.duzimei.blog.proxy.LogProxy" factory-method="getInstance">
<!-- 指定 getInstance() 方法的参数, 即要被代理的对象 -->
<constructor-arg ref="userDao"/>
</bean>
- 在 UserService.class 中将注入的对象指定为代理对象:proxyUserDao 即可
@Service
public class UserService implements IUserService {
private IUserDao userDao;
@Resource(name="proxyUserDao")
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
}
使用注解优化输出
- 新建一个 Annotation:LogInfo,添加如下代码
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogInfo {
public String value() default "";
}
- 将该注解添加在方法上,并添加要输出的日志信息
public interface IUserDao {
@LogInfo("添加 User")
public void add(User user);
@LogInfo("删除 User")
public void delete(int id);
}
- 修改 LogProxy.class 中的 invoke 方法
// 有了代理对象后,不管这个代理对象执行什么方法, 都会调用下面这个 invoke 方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.isAnnotationPresent(LogInfo.class)) {
LogInfo logInfo = method.getAnnotation(LogInfo.class);
System.out.println(new Date() + " ---> 进行了操作: " + logInfo.value());
}
Object object = method.invoke(target, args);
return object;
}
测试一下