一、回顾
但是我们之前MVC时候,在页面上,为什只用Controller,不用其他的呢?
用其他的好使吗?(我们可以在这里看到,出现404的字样)
@Service @ResponseBody public class TestController { @RequestMapping("/test") public String test(){ return "测试Controller和其他注解的区别"; } }
但是Controller就是好使的,事实上Spring对Controller有更屌的权限
二、@Bean用法
五大注解只能加在类上,并且只能加在自己的代码上
如果我引入一个第三方的jar包,也希望交给Spring管理,是没有办法加五大注解
第一个应用场景:可以使用@Bean, @Bean是方法注解
在这里,我们可以看到一个问题,就是两个引用指向的是一个对象(看后面的那几位,说明地址相同)
第二个应用场景:那么假如说要求是一个类,定义多个对象,比如说数据库操作,定义多个数据源使用@Bean
@Bean相当于是一个上交作业的过程,交完了作业,要告诉老师,交完作业了
所以也就是说@Bean要搭配五大注解来使用并且当一个类型存在多个bean中,采用多个Bean的时候,我们就不能使用类型来获取对象了。
我们上节课学的注释
是getBean+方法名(小驼峰形式,特殊情况(两个首字母都是大写,那么她就会变成小写)
@Bean需要加的是方法名(方法名不遵守小驼峰形式)
如何进行相应的传递参数
那么我们在应用中,一般不会让写死
假如对Bean的方法中的内容进行传参数,则定义一个这种方法,当然现在这个也是死的,但是以后可以用这种方法变成“活的”
@Configuration public class BeanConfig { @Bean public String name(){ return "zhangsan"; } @Bean public UserInfo UserInfo(String string){ UserInfo userInfo=new UserInfo(); userInfo.setName(string); return userInfo; }
Spring的扫描文件约定
SpringBoot是属于我们的开发框架(其实叫做开发框架,更感觉像是打开idea,后呈现的这个结构)
SpringBoot特点:约定大于配置,约定到,放到哪里就扫描当前文件夹里面的所有文件,但是假如说你硬是想在一个小的目录里面去执行(也有方法,加路径)(约定的体现之一扫描路径,默认的扫描路径是:启动类所在的目录及其子孙目录)
解决方式就是
//默认扫描当前类的目录及子目录
在前面加上这个注解(路径自己填)@ComponentScan("com.example")
@ComponentScan("com.example") @SpringBootApplication public class IoCtryApplication { public static void main(String[] args) { //启动类是帮助我们启动spring,这个命令可以返回一个spring
DI详解
DI依赖注入,属性装配“依赖装配”,
只要加上这些依赖注入(就跟我们导包一样,没导包不能用)
1.属性注入 @Autowired
(相当于导游,带着去找这个东西)和上面那个匹配的一致,和那个@Bean传递参数一样。
@Controller public class UserController { //⚠️假如没有下面的这个Autowired注释,那么就会报空指针异常 @Autowired private UserService userService; public void prin(){ userService.doService(); System.out.println("春节快乐"); } }
UserController userController=context.getBean(UserController.class); userController.prin();
2.构造方法注入
如下图
@Controller public class UserController { //@Autowired private UserService userService; private UserInfo userInfo; //⚠️注意此时加完构造函数之后,还要把无参数的也写一遍,因为无参数的构造函数,有很多东西在用,所以一旦经过修改,就会让使用无参数的报错。 public UserController(){ } @Autowired public UserController(UserService userService){ this.userService=userService; } public UserController(UserInfo userInfo,UserService userService){ this.userService=userService; this.userInfo=userInfo; } public void prin(){ userService.doService(); System.out.println("春节快乐"); }
3.Setter方法注入
三种注入的优缺点
1.属性注入:
优点:简洁方便
缺点:只能用于IOC容器,如果非IOC容器无法使用,并且只有在使用的时候才会出现NPE(空指针异常),并且不能修饰Final。
2.构造函数注入:
优点:
(1).可以注入final属性(通过构造方法的形式)。
(2).注入的对象不会被修改(因为除非你再new,不然构造方法不能被再次调用),依赖对象使用之前一定会被初始化,因为依赖在类的构造方法中执行的,构造方法是类加载阶段就会执行的方法
(3).通用型好:构造方法是JDK支持的
缺点:
代码会比较繁琐
Setter注入
优点:方便类实例化之后,重新对该对象进行配置或者注入
缺点:不能修饰Final,注入的对象肯会被改变,因为setter方法可能会被多次调用,就有被修改的风险。
当程序同一个类型,多个对象时候,使用@AutoWired会报错
这里说的情况是这样的一个代码
package com.example.IOCtry; import com.example.IOCtry.config.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; @Controller public class UserController { @Autowired //⚠️ private UserService userService; @Autowired //⚠️ private UserInfo userInfo; //注意此时加完构造函数之后,还要把无参数的也写一遍,因为无参数的构造函数,有很多东西在用,所以一旦经过修改,就会让使用无参数的报错。 //public UserController(){ //} // //public UserController(UserService userService){ // this.userService=userService; //} // // public UserController(UserInfo userInfo,UserService userService){ // this.userService=userService; // this.userInfo=userInfo; // } // @Autowired // public void setUserController(UserService userService){ // this.userService=userService; // } public void prin(){ userService.doService(); System.out.println(userInfo); System.out.println("春节快乐"); } }
改法一需要改属性名字:让属性名和方法名字一致
package com.example.IOCtry; import com.example.IOCtry.config.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; @Controller public class UserController { @Autowired private UserService userService; @Autowired private UserInfo UserInfo1; //⚠️这个名字改成和方法名字一摸一样 //注意此时加完构造函数之后,还要把无参数的也写一遍,因为无参数的构造函数,有很多东西在用,所以一旦经过修改,就会让使用无参数的报错。 //public UserController(){ //} // //public UserController(UserService userService){ // this.userService=userService; //} // // public UserController(UserInfo userInfo,UserService userService){ // this.userService=userService; // this.userInfo=userInfo; // } // @Autowired // public void setUserController(UserService userService){ // this.userService=userService; // } public void prin(){ userService.doService(); System.out.println(UserInfo1); System.out.println("春节快乐"); } }
不想改名的第二种方法:加上@Primary
//这个是在另一个类中搞的方法 package com.example.IOCtry.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration public class BeanConfig { @Bean public String name(){ return "zhangsan"; } @Bean public String name2(){ return "wangwu"; } // ⚠️@Primary这个只有加上,程序才会不发生错误,会执行这个Setter方法 @Bean public UserInfo UserInfo1(String name2){ UserInfo userInfo=new UserInfo(); userInfo.setName(name2); return userInfo; } @Bean public UserInfo userInfo2(){ UserInfo userInfo=new UserInfo(); userInfo.setId(2); userInfo.setAge(22); userInfo.setName("lclyr"); return userInfo; } }
改法3(优先):使用@Qualifier
package com.example.IOCtry; import com.example.IOCtry.config.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; @Controller public class UserController { @Autowired private UserService userService; @Qualifier("userInfo2") //⚠️ @Autowired private UserInfo userInfo; //注意此时加完构造函数之后,还要把无参数的也写一遍,因为无参数的构造函数,有很多东西在用,所以一旦经过修改,就会让使用无参数的报错。 //public UserController(){ //} // //public UserController(UserService userService){ // this.userService=userService; //} // // public UserController(UserInfo userInfo,UserService userService){ // this.userService=userService; // this.userInfo=userInfo; // } // @Autowired // public void setUserController(UserService userService){ // this.userService=userService; // } public void prin(){ userService.doService(); System.out.println(userInfo); System.out.println("春节快乐"); } }
改法4(优先):使用@Resource(name="userInfo2")
package com.example.IOCtry; import com.example.IOCtry.config.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import javax.annotation.Resource; @Controller public class UserController { @Autowired private UserService userService; //@Qualifier("userInfo2") @Resource(name="userInfo2") @Autowired private UserInfo userInfo; //注意此时加完构造函数之后,还要把无参数的也写一遍,因为无参数的构造函数,有很多东西在用,所以一旦经过修改,就会让使用无参数的报错。 //public UserController(){ //} // //public UserController(UserService userService){ // this.userService=userService; //} // // public UserController(UserInfo userInfo,UserService userService){ // this.userService=userService; // this.userInfo=userInfo; // } // @Autowired // public void setUserController(UserService userService){ // this.userService=userService; // } public void prin(){ userService.doService(); System.out.println(userInfo); System.out.println("春节快乐"); } }
三、常见面试题Autowired VS Resource
@Autowired:是Spring开发的框架,@Resource是JDK提供的框架
@Autowired:默认是按照类型来去注入,假如说同一个类型存在多个对象,那么就按名称匹配,假如名称匹配不上,那么就会报错,相对于Autowired来说,@Resource支持更多的参数设置,如name设置,根据名称获取Bean