网站设计开发的难点,佛山专业建站公司,学校资源网站建设方案,企业建设网站的案例目录 一、前言二、案例1 代码2 自定义代理类【静态代理】2.1 一个接口多个实现#xff0c;到底注入哪个依赖呢#xff1f;2.1.1 Primary注解2.1.2 Resource注解#xff08;指定name属性#xff09;2.1.3 Qualifier注解 2.2 面向接口编程2.3 如果没接口咋办呢#xff1f;2.… 目录 一、前言二、案例1 代码2 自定义代理类【静态代理】2.1 一个接口多个实现到底注入哪个依赖呢2.1.1 Primary注解2.1.2 Resource注解指定name属性2.1.3 Qualifier注解 2.2 面向接口编程2.3 如果没接口咋办呢2.3.1 示例2.3.2 继承 3 动态代理 一、前言
在【对AOP的理解】中提到过代理模式。本篇文章进一步谈谈我对代理模式的理解。
二、案例
1 代码
RestController
RequestMapping(/user)
public class UserController {Resourceprivate UserService userService;PostMapping(/login)public UserVO login(RequestBody LoginRequest loginRequest) {UserDO userDO userService.login(loginRequest.getUsername(), loginRequest.getPassword());return UserVO.builder().username(userDO.getUsername()).password(userDO.getPassword()).build();}
}public interface UserService {UserDO login(String username, String password);
}Service
public class UserServiceImpl implements UserService {Resourceprivate LoginProcess loginProcess;Overridepublic UserDO login(String username, String password) {return loginProcess.login(username, password);}
}Component
public class LoginProcess {public UserDO login(String username, String password) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}return new UserDO().setUsername(forrest).setPassword(123456);}
}我们想知道“登录”过程耗费的时间即loginProcess.login(username, password);耗费的时间。我们希望通过自定义代理类来实现。
2 自定义代理类【静态代理】
Slf4j
Service
public class UserProxyServiceImpl implements UserService {Resourceprivate UserServiceImpl userServiceImpl;Overridepublic UserDO login(String username, String password) {long startTimestamp System.currentTimeMillis();UserDO userDO userServiceImpl.login(username, password);log.info(login cost {} ms, System.currentTimeMillis() - startTimestamp);return userDO;}
}如果这么写很显然启动时会报错No qualifying bean of type structure.proxy.example3.service.UserService available: expected single matching bean but found 2: userProxyServiceImpl,userServiceImpl
RestController
RequestMapping(/user)
public class UserController {Resourceprivate UserService userService;...
}UserService是接口有两个实现类Spring不知道到底要注入哪个bean因此报错了。
2.1 一个接口多个实现到底注入哪个依赖呢
在Spring框架中当存在多个相同类型的bean时可以通过三种主要方式来指定注入哪一个bean使用Primary注解、Resouce注解指定name属性和Qualifier注解。
2.1.1 Primary注解
Slf4j
Service
Primary
public class UserProxyServiceImpl implements UserService {...
}2.1.2 Resource注解指定name属性
RestController
RequestMapping(/user)
public class UserController {Resource(name userProxyServiceImpl)private UserService userService;...
}IDEA的友好提示 妈妈再也不担心我注不对bean了:)
2.1.3 Qualifier注解
Resource(name “userProxyServiceImpl”)相当于
Autowired
Qualifier(userProxyServiceImpl)RestController
RequestMapping(/user)
public class UserController {AutowiredQualifier(userProxyServiceImpl)private UserService userService;...
}同样IDEA提供了友好的提示
2.2 面向接口编程
我们通过改变使用的bean从UserServiceImpl换成了UserProxyServiceImpl就新增了一些逻辑例如记录“登录”消耗的时间。对调用者完全是无感的。 这就是通过接口来解耦了调用方和实现方调用方–接口–实现方。
2.3 如果没接口咋办呢
2.3.1 示例
RestController
RequestMapping(/user)
public class UserController {Resourceprivate UserServiceImpl userService;PostMapping(/login)public UserVO login(RequestBody LoginRequest loginRequest) {UserDO userDO userService.login(loginRequest.getUsername(), loginRequest.getPassword());return UserVO.builder().username(userDO.getUsername()).password(userDO.getPassword()).build();}
}Service
public class UserServiceImpl {Resourceprivate LoginProcess loginProcess;public UserDO login(String username, String password) {return loginProcess.login(username, password);}
}2.3.2 继承
RestController
RequestMapping(/user)
public class UserController {
// Resource
// private UserServiceImpl userService;Resourceprivate UserProxyServiceImpl userService;...
}Slf4j
Service
public class UserProxyServiceImpl extends UserServiceImpl {Resourceprivate UserServiceImpl userServiceImpl;Overridepublic UserDO login(String username, String password) {long startTimestamp System.currentTimeMillis();UserDO userDO userServiceImpl.login(username, password);log.info(login cost {} ms, System.currentTimeMillis() - startTimestamp);return userDO;}
}很显然所有用到UserServiceImpl的地方都要换成UserProxyServiceImpl。麻烦啊因此如果依赖的实现方可能变化一定要面向接口编程啊 如果第三方没提供接口也要自定义一个接口来解耦调用方和实现方
3 动态代理
详见对AOP的理解