Spring 使用 FactoryBean 实现代理,并通过代理对象执行数据库操作

本文介绍了如何使用 Spring 的 FactoryBean 实现代理,并通过代理对象执行数据库操作。代码中存在两个问题:UserServiceImpl 中的 UserMapper 没有被注入,以及 UserServiceProxyFactoryBean 中创建的代理对象没有正确设置目标对象。文章详细说明了问题的解决方法,并给出了修改后的代码。

问题描述

我想要把 UserService 的实例通过 FactoryBean 的方式注册到容器中,要求从容器中取出的实例,直接执行 insert 方法,能够直接插入到数据库中。以下是我的代码,哪里有问题吗?

@Data
public class User {
    Integer id;
    String username;
    String password;
    Integer age;
}

@Configuration
@ComponentScan("com.cskaoyan")
public class Demo2Configuration {

}

@Component
public class UserServiceProxyFactoryBean implements FactoryBean<UserService> {

    @Autowired
    UserService userService;

    @Override
    public UserService getObject() throws Exception {
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] args) throws Throwable {
                SqlSession sqlSession = MyBatisUtil.getSqlSession();
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                Object result = method.invoke(userMapper, args);
                sqlSession.commit();
                sqlSession.close();
                return result;
            }
        };
        Object proxy = Proxy.newProxyInstance(
                getClass().getClassLoader(),
                new Class<?>[] { UserService.class },
                invocationHandler
        );
        return (UserService) proxy;
    }

    @Override
    public Class<?> getObjectType() {
        return UserService.class;
    }
}

public interface UserService {
    public String queryNameById(Integer id);
    public int insertUser(User user);

}

@Component
public class UserServiceImpl implements UserService{
    UserMapper userMapper;//如果没有处理,这个值为null


    public String queryNameById(Integer id){
        //sqlSession = MyBatisUtil.getSqlSession();
        //UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //userMapper = sqlSession.getMapper();
        String s = userMapper.selectNameById(id);
        //sqlSession.commit();
        //sqlSession.close();
        return s;
    }

        //sqlSession = MyBatisUtil.getSqlSession();
        //UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    public int insertUser(User user){
        int i = userMapper.insertUser(user);
        //sqlSession.commit();
        //sqlSession.close();
        return i;
    }
}

public interface UserMapper {

    String selectNameById(@Param("id") Integer id);

    int insertUser(User user);
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cskaoyan.mapper.UserMapper">

    <select id="selectNameById" resultType="string">
        select username from cskaoyan_user where id = #{id}
    </select>

    <insert id="insertUser">
        insert into cskaoyan_user (username,password,age) values (#{username},#{password},#{age})
    </insert>
</mapper>

下面这个是测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Demo2Configuration.class)
public class MyTest {
    @Qualifier("userServiceProxyFactoryBean")
    @Autowired
    UserService userService;
    @Test
    public void myTest3(){
        User user = new User();
        user.setUsername("大侠");
        user.setPassword("666666");
        user.setAge(18);
        int i = userService.insertUser(user);
        System.out.println(i);
    }

问题分析

代码中存在几个问题:

  1. UserServiceImpl 类中的 UserMapper 没有被注入,导致 userMapper 为空。可以通过在 UserMapper 属性上添加 @Autowired 注解来解决。

  2. UserServiceProxyFactoryBean 中的 getObject 方法中创建的代理对象没有正确设置目标对象,导致执行 insert 方法时会报错。可以通过在 InvocationHandler 中将目标对象设置为 userService 来修复。

解决方案

修改后的代码如下:

@Data
public class User {
    Integer id;
    String username;
    String password;
    Integer age;
}

@Configuration
@ComponentScan("com.cskaoyan")
public class Demo2Configuration {

}

@Component
public class UserServiceProxyFactoryBean implements FactoryBean<UserService> {

    @Autowired
    UserService userService;

    @Override
    public UserService getObject() throws Exception {
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] args) throws Throwable {
                SqlSession sqlSession = MyBatisUtil.getSqlSession();
                UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                Object result = method.invoke(userMapper, args);
                sqlSession.commit();
                sqlSession.close();
                return result;
            }
        };
        Object proxy = Proxy.newProxyInstance(
                getClass().getClassLoader(),
                new Class<?>[] { UserService.class },
                invocationHandler
        );
        ((Proxy) proxy).setTarget(userService);
        return (UserService) proxy;
    }

    @Override
    public Class<?> getObjectType() {
        return UserService.class;
    }
}

public interface UserService {
    public String queryNameById(Integer id);
    public int insertUser(User user);
}

@Component
public class UserServiceImpl implements UserService{

    @Autowired
    UserMapper userMapper;

    public String queryNameById(Integer id){
        String s = userMapper.selectNameById(id);
        return s;
    }

    public int insertUser(User user){
        int i = userMapper.insertUser(user);
        return i;
    }
}

public interface UserMapper {

    String selectNameById(@Param("id") Integer id);

    int insertUser(User user);
}

代码说明

  1. 在 UserServiceImpl 类中,我们添加了 @Autowired 注解,将 UserMapper 注入到 UserServiceImpl 中。

  2. 在 UserServiceProxyFactoryBean 中,我们修改了 getObject 方法,将目标对象设置为 userService。

  3. 在测试类 MyTest 中,我们通过 @Qualifier 注解指定了要注入的 bean 的名称,并使用 userService.insertUser 方法执行插入操作。

总结

本文介绍了如何使用 Spring 的 FactoryBean 实现代理,并通过代理对象执行数据库操作。代码中存在两个问题:UserServiceImpl 中的 UserMapper 没有被注入,以及 UserServiceProxyFactoryBean 中创建的代理对象没有正确设置目标对象。文章详细说明了问题的解决方法,并给出了修改后的代码。

希望对你有帮助!

Spring 使用 FactoryBean 实现代理,并通过代理对象执行数据库操作

原文地址: https://www.cveoy.top/t/topic/nQKV 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录