@Component
(@Controller、@Service、@Repository):自动创建一个实例并装配到Spring容器中(放到IOC中)
【Ps.写好的其他项目jar放到pom,Spring自动装配,简单好用,简直冒了泡了】
@Bean
:手动创建一个实例,并保留在IOC中。
@Bean的好处:麻烦一点,但自定义性更强。当我们引用第三方库中的类需要装配到Spring容器时,则只能通过@Bean来实现~(因为你并不能改他的源代码在他类上加个@Component ,所以只能这么玩了。
引申:代码回调函数也是起这个作用)
@SpringBootApplication
public class Application {
@Bean
BookingService bookingService() {
return new BookingService();
}
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
BookingService bookingService = ctx.getBean(BookingService.class);
bookingService.book("Alice", "Bob", "Carol");
}
}
@Autowired
:织入(Spring上下文已有实例(已注入IOC),@Autowired只是取一下)
@Autowired说“请给我一个该类的实例,例如,我之前用@Bean注释创建的一个实例进入IOC了”。
@Autowired一般用在变量上,spring容器会自动注入值。
如果用在方法上:
@Autowired(required = false)
public void setRedisTemplate(RedisTemplate redisTemplate) {
RedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
this.redisTemplate = redisTemplate;
}
spring容器会在类加载后自动注入这个方法的参数,并执行一遍方法。
总结: @Autowired注解作用在方法上
(1)该方法如果有参数,会使用autowired的方式在容器中查找是否有该参数
(2)会执行该方法
(3)这就像static{}块语句会初始化执行,但顺序不一样(static{}比↑快)。
实际项目一般是@Component配合@Autowired联用
但是改成这样玩也行:
@SpringBootApplication
public class Application {
@Autowired
BookingService bookingService;
@Bean
BookingService bookingService() {
return new BookingService();
}
public static void main(String[] args) {
bookingService.book("Alice", "Bob", "Carol");
}
}
在这种情况下,@Bean注释为Spring提供了BookingService,并加以@Autowired利用。但这是一个毫无意义的示例,因为你都在同一个类中使用它们…不如下面就直接new对象呢还能少写上面那几行呢。
但是如果你在一个类中@Bean定义对象实例(注册到IOC),而在另一个类中@Autowired使用。那@Bean+@Autowired就变得很有用。
补充阅读:
@Configuration和@Component区别
最近知道: A注解上面有几个注解,其他地方用到这个A注解,会是叠加效果~那么,这就又可以(借助注解)抽象一层了(不过注解本质就是接口啊,所以,能实现抽象抽取的效果,好像也是理所当然的哈_)
例如,下面的oaScenePeopleHandlers能自动注入
private Map<String, OaScenePeopleHandler> oaScenePeopleHandleMap;
@Autowired
public void setOaScenePeopleHandleMap(List<OaScenePeopleHandler> oaScenePeopleHandlers) {
// 注入各种场景类型的处理类
oaScenePeopleHandleMap = oaScenePeopleHandlers.stream().collect(
Collectors.toMap(orderHandler -> AnnotationUtils.findAnnotation(orderHandler.getClass(), OaScenePeopleHandlerType.class).sceneType(),
v -> v, (v1, v2) -> v1));
}
是因为
public interface OaScenePeopleHandler {
void sendSecnePeoplePermissionHandle(OaScenePeopleEntity oaScenePeopleEntity);
}
@OaScenePeopleHandlerType(sceneType="1")
public class ChangJingHandler implements OaScenePeopleHandler {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface OaScenePeopleHandlerType {
// 1.场景 2.设备
String sceneType();
}
破案了,@Service出现了,原来在这呢。
如果注掉了就会报错了
以后有空可以把上述代码用@Bean重写一遍玩玩(这不找麻烦呢不是,故意变复杂)。
Ps.
能用@Autowired等注解有个另外的隐藏前提(除了织入的类本身得有先注入到IOC):被写这些注解代码的这个类,也得教给了IOC(Spring管理),才能里面写了这些注解,这些注解会被扫描(?会有意义?),否则报空指针异常
如:
@Autowired
private WeChatSendMsgUtils weChatSendMsgUtils;
@Test
public void testSendWx2(){
String templateId=systemProperties.getExamineConfirm();
String url="www.baidu.com";
//我的测试号
String toUserWxId="oLh_dvztrOLfkDm5RJ6F_ngBgByQ";
//2020年6月30日 考虑思路:sendWxMsg可以是静态方法不好用,但那么wxMpService注入也得静态的。WeChatSendMsgUtils 得交给Spring。或者 new WeChatSendMsgUtils().sendWxMsg也行【但是weChatSendMsgUtils内容里有注解,所以该类本身也得交给IOC才能里面的注解有意义,那么,既然该类也交给IOC,我何不也用Spring注入呢,所以,这里没用new。那么,静态也没啥更方便了,所以静态又没有用】
weChatSendMsgUtils.sendWxMsg(
templateId,
url,
toUserWxId,
new WxMsgDto("AA的随行BB接受了访客邀请!",
"普普",
"面试",
"2019-01-02 9:00 - 2019-01-02 9:00",
"1666666666",
"更多信息,请点击详情进行查看"));
}
@Component
public class WeChatSendMsgUtils {
@Resource
private WxMpService wxMpService;
/**
* 只支持三行或四行的微信模板
* @param templateId 模板id
* @param url 跳转url
* @param toUserWxId 目标wxId
* @param wxMsgDto 信息数组/集合
*/
public void sendWxMsg(String templateId, String url, String toUserWxId, WxMsgDto wxMsgDto) {
try {
msg = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
如果WeChatSendMsgUtils.java不加@Component(或者@Service…),那么 @Resource
private WxMpService wxMpService; 会是无效的,使用时会是空的。(可能是里面的注解会无意义,Spring会不扫描吧)
代码里黏贴出来: //2020年6月30日 考虑思路:sendWxMsg可以是静态方法不好用,但那么wxMpService注入也得静态的。WeChatSendMsgUtils 得交给Spring。或者 new WeChatSendMsgUtils().sendWxMsg也行【但是weChatSendMsgUtils内容里有注解,所以该类本身(“包住这些注解的那个类”,它没交给Spring,那么里面的东西也没交给Spring,感觉挺有这道理的[可以理解成“没扫描”吗]【他(本身)也得注入,他里面的注入(里面注解的效果)才能顺带这一起注入。他被交给Spring管理,他才能有从Spring取东西的资格?/能力?/权利?/权力?】)也得交给IOC才能里面的注解有意义,那么,既然该类也交给IOC,我何不也用Spring注入呢,所以,这里没用new 干脆全用Spring管理。那么,静态也没啥更方便了,所以静态又没有用的必要】
Ps.某注解定义时,上面放注解,那么用该某注解时,是会有叠加效果的(上文说过了。。。“叠加作用/叠加效果,可以理解成接口的多继承”)。(参见springboot启动项。和我的有道笔记策略模式破案了。)
@Component
public class WechatAccount {
@Autowired
private static WeChatAccountConfig weChatAccountConfig ;
//(测试、正式)公众号
public String APPID = weChatAccountConfig.getAppId();
public String APPSECRET = weChatAccountConfig.getAppSecret();
public String TOKEN = weChatAccountConfig.getToken();
public String ENCODINGAESKEY =weChatAccountConfig.getAesKey();
}
报错:加载时null(应该是weChatAccountConfig 对象null了)
尝试解析/解读/分析:因为有加载顺序,全局静态变量应该快于方法吧,所以报空。
解决尝试:
@Component
public class WechatAccount {
//@Autowired
// private static WeChatAccountConfig weChatAccountConfig ;
//(测试、正式)公众号
public static String APPID;
public static String APPSECRET;
public static String TOKEN;
public static String ENCODINGAESKEY;
@Autowired
public void initWechatAccount(WeChatAccountConfig weChatAccountConfig){
APPID = weChatAccountConfig.getAppId();
System.out.println("hhhhhh"+APPID);
APPSECRET = weChatAccountConfig.getAppSecret();
TOKEN = weChatAccountConfig.getToken();
ENCODINGAESKEY =weChatAccountConfig.getAesKey();
}
}