Spring 使用 FactoryBean 实现代理,并通过代理对象执行数据库操作
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);
}
问题分析
代码中存在几个问题:
-
UserServiceImpl 类中的 UserMapper 没有被注入,导致 userMapper 为空。可以通过在 UserMapper 属性上添加 @Autowired 注解来解决。
-
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);
}
代码说明
-
在 UserServiceImpl 类中,我们添加了 @Autowired 注解,将 UserMapper 注入到 UserServiceImpl 中。
-
在 UserServiceProxyFactoryBean 中,我们修改了 getObject 方法,将目标对象设置为 userService。
-
在测试类 MyTest 中,我们通过 @Qualifier 注解指定了要注入的 bean 的名称,并使用 userService.insertUser 方法执行插入操作。
总结
本文介绍了如何使用 Spring 的 FactoryBean 实现代理,并通过代理对象执行数据库操作。代码中存在两个问题:UserServiceImpl 中的 UserMapper 没有被注入,以及 UserServiceProxyFactoryBean 中创建的代理对象没有正确设置目标对象。文章详细说明了问题的解决方法,并给出了修改后的代码。
希望对你有帮助!
原文地址: https://www.cveoy.top/t/topic/nQKV 著作权归作者所有。请勿转载和采集!