在Springboot项目中我们可以通过main方法启动项目,在需要启动的主类中我们需要加入@SpringBootApplication这个注解,告诉spring boot,这个是程序的入口。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
不加这个注解是无法启动项目的,下面查看下SpringBootApplication,本质是一个接口,源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
Class<?>[] exclude() default {};
//根据class来排除特定的类加入spring容器,传入参数value类型是class类型
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
/
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {};
//根据class name来排除特定的类加入spring容器,传入参数value类型是class的全类名字符串数组
/*
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* @return base packages to scan
* @since 1.3.0
/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
//指定扫描包,参数是包名的字符串数组
/*
* Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
//扫描特定的包,参数类似是Class类型数组
}
在这个类上有三个注解:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
我们可以用这三个注解代替@SpringBootApplication:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
其中
@SpringBootConfiguration:继承自@Configuration,表示SpringBoot的配置注解,功能一致,标注当前的类为配置类,并将当前类内声明的一个或多个@Bean注解标记的方法实例纳入到Spring容器中,并且实例名就是方法名。@EnableAutoConfiguration:表示自动配置,作用是启动自动的配置,意思就是Springboot根据你添加的jar包来配置你的项目的默认配置,比如根据spring-boot-starter-web,来判断你的项目是否需要添加webmvc和tomcat,就会自动帮你配置web项目中所需要的默认配置。
@ComponentScan:表示SpringBoot扫描Bean的规则,比如扫面哪些包,扫描当前包及其子包下被@Component,@Controller,@Service,@Repository注解标记的类并纳入到spring容器中进行管理。是以前的<context:component-scan>
@Configuration:加了这个注解的类被认为是SpringBoot的配置类,我们知道可以在application.yml/properties设置一些配置,也可以通过代码设置配置。
如果我们要通过代码设置配置,就必须在这个类上加这个注解,通俗的讲,@Configuration一般与@Bean(注释是用来表示一个方法实例化,配置和初始化是由 Spring IoC 容器管理的一个新的对象)注解配合使用,用@Configuration注解类等价于XML中配置beans,用@Bean注解方法等价与XML中配置bean:
<beans>
<bean id = "userService" class="com.user.UserService">
<property name="userDAO" ref = "userDAO">
</property>
</bean>
<bean id = "userDAO" class="com.user.UserDAO">
</bean>
</beans>
——>等价于:
package org.spring.com.user;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean public UserService getUserService(){
UserService userService = new UserService();
userService.setUserDAO(null);
return userService;
}
@Bean public UserDAO getUserDAO(){
return new UserDAO();
}
}
package org.spring.com.user;
public class UserService {
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
package org.spring.com.user;
public class UserDAO {
}
@Configuration
public class WebConfig extends WebMvcConfigurationSupport{
@Override
protected void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(new ApiInterceptor());
}
}
不过,Springboot官方推荐使用SpringBootConfiguration来代替Configuration
@Bean是方法级别上的注解,主要添加在@Configuration或者@SpringBootConfiguration注解的类,有时也可以添加在@Component注解的类,作用是定义一个bean
注意:使用@ComponentScan注解代替@SpringBootApplication注解,也可以正常运行程序。原因是@SpringBootApplication中包含@ComponentScan,并且springboot会将入口类看作是一个@SpringBootConfiguration标记的配置类,所以定义在入口类Application中的Runnable也可以纳入到容器管理。
SpringBootApplication执行流程图如下:
番外:@Autowired与@Resource:
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
1.@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
@Autowired()@Qualifier("baseDao")
privateBaseDao baseDao;
@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="baseDao")
privateBaseDao baseDao;
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
@Autowired//默认按type注入
@Qualifier("cusInfoService")//一般作为@Autowired()的修饰用
@Resource(name="cusInfoService")//默认按name注入,可以通过name和type属性进行选择性注入
一般@Autowired和@Qualifier一起用,@Resource单独用。
当然没有冲突的话@Autowired也可以单独用
其他常用注解:
--定义Bean的注解
@Controller
@Controller("Bean的名称")
定义控制层Bean,如Action
@Service
@Service("Bean的名称")
定义业务层Bean
@Repository
@Repository("Bean的名称")
定义DAO层Bean
@Component
定义Bean, 不好归类时使用.
--自动装配Bean (选用一种注解就可以)
@Autowired (Srping提供的)
默认按类型匹配,自动装配(Srping提供的),可以写在成员属性上,或写在setter方法上
@Autowired(required=true)
一定要找到匹配的Bean,否则抛异常。 默认值就是true
@Autowired
@Qualifier("bean的名字")
按名称装配Bean,与@Autowired组合使用,解决按类型匹配找到多个Bean问题。
@Resource JSR-250提供的
默认按名称装配,当找不到名称匹配的bean再按类型装配.
可以写在成员属性上,或写在setter方法上
可以通过@Resource(name="beanName") 指定被注入的bean的名称, 要是未指定name属性, 默认使用成员属性的变量名,一般不用写name属性.
@Resource(name="beanName")指定了name属性,按名称注入但没找到bean, 就不会再按类型装配了.
@Inject 是JSR-330提供的
按类型装配,功能比@Autowired少,没有使用的必要。
--定义Bean的作用域和生命过程
@Scope("prototype")
值有:singleton,prototype,session,request,session,globalSession
@PostConstruct
相当于init-method,使用在方法上,当Bean初始化时执行。
@PreDestroy
相当于destory-method,使用在方法上,当Bean销毁时执行。
--声明式事务
@Transactional
@Autowired @Resource @Qualifier的区别
实用理解:@Autowired @Resource 二选其一,看中哪个就用哪个。
简单理解:
@Autowired 根据类型注入,
@Resource 默认根据名字注入,其次按照类型搜索
@Autowired @Qualifie("userService") 两个结合起来可以根据名字和类型注入
复杂理解:
比如你有这么一个Bean
@Service(“UserService”)
public Class UserServiceImpl implements UserService{};
现在你想在UserController 里面使用这个UserServiceImpl
public Class UserController {
@AutoWire //当使用这个注入的时候上面的 UserServiceImpl 只需要这样写 @Service,这样就会自动找到UserService这个类型以及他的子类型。UserServiceImpl 实现了UserService,所以能够找到它。不过这样有一个缺点,就是当UserService实现类有两个以上的时候,这个时候会找哪一个呢,这就造成了冲突,所以要用@AutoWire注入的时候要确保UserService只有一个实现类。
@Resource 默认情况下是按照名称进行匹配,如果没有找到相同名称的Bean,则会按照类型进行匹配,有人可能会想了,这下好了,用这个是万能的了,不用管名字了,也不用管类型了,但这里还是有缺点。首先,根据这个注解的匹配效果可以看出,它进行了两次匹配,也就是说,如果你在UserService这个类上面这样写注解,@Service,它会怎么找呢,首先是找相同名字的,如果没有找到,再找相同类型的,而这里的@Service没有写名字,这个时候就进行了两次搜索,显然,速度就下降了许多。也许你还会问,这里的@Service本来就没有名字,肯定是直接进行类型搜索啊。其实不是这样的,UserServiceImpl 上面如果有@Service默认的名字 是这个userServiceImpl,注意看,就是把类名前面的大写变成小写,就是默认的Bean的名字了。 @Resource根据名字搜索是这样写@Resource("userService"),如果你写了这个名字叫userService,那么UserServiceImpl上面必须也是这个名字,不然还是会报错。
@Autowired @Qualifie("userService") 是直接按照名字进行搜索,也就是说,对于UserServiceImpl 上面@Service注解必须写名字,不写就会报错,而且名字必须是@Autowired @Qualifie("userService") 保持一致。如果@Service上面写了名字,而@Autowired @Qualifie() ,一样会报错。
private UserService userService;
}
说了这么多,可能你有些说晕了,那么怎么用这三个呢,要实际的工作是根据实际情况来使用的,通常使用AutoWire和@Resource多一些,bean的名字不用写,而UserServiceImpl上面能会这样写 @Service("userService")。这里的实际工作情况,到底是什么情况呢?说白了就是整个项目设计时候考虑的情况,如果你的架构设计师考虑的比较精细,要求比较严格,要求项目上线后的访问速度比较好,通常是考虑速度了。这个时候@AutoWire没有@Resource好用,因为@Resource可以根据名字来搜索,是这样写的@Resource("userService")。这个@Autowired @Qualifie("userService") 也可以用名字啊,为什么不用呢,原因很简单,这个有点长,不喜欢,增加工作量。因为根据名字搜索是最快的,就好像查数据库一样,根据Id查找最快。因为这里的名字与数据库里面的ID是一样的作用。这个时候,就要求你多写几个名字,工作量自然就增加了。而如果你不用注解,用xml文件的时候,对于注入Bean的时候要求写一个Id,xml文件时候的id就相当于这里的名字。
说了那么多没用,你能做的就是简单直接,什么最方便就用什么,
你就直接用@Resource得了,如果你喜欢用@AutoWired也行,不用写名字
例子:
@Resource使用注意事项
例:
@Resource
CityDao citydao;
【1】 则首先根据类名,将类名首字母小写得到cityDao,然后去Spring的配置文件中寻找id为cityDao的bean,即进行名称匹配
【2】若Spring的配置文件中没有id为cityDao的bean,则再根据类型进行匹配,在配置文件中寻找class为CityDao的bean
@Autowired使用注意事项
例:
@Autowired
CityDao cityDao;
【1】直接根据类型进行匹配,Spring会去配置文件中寻找class为CityDao的bean
@Qualifer使用注意事项
例:
@Autowired
@Qualifer("cityDao2")
CityDao cityDao;
【1】@Qualifer不能单独使用,否则会出现空指针错误
【2】需要配合@Autowired使用,会从Spring配置文件中寻找id为cityDao2的bean,即进行名称匹配