注解的基础概念
指的是在类或者方法上加入特定的注解(@XXXX),完成特定功能的开发。
为什么要讲解注解编程?
- 注解开发非常方便,代码简洁
- 开发速度大大提高
- Spring开发一个潮流
Spring从2.x开始引入注解,Spring3.x开始完善注解,Springboot推广开来,普及注解。
注解作用
- 替换xml这种配置形式,简化配置
@Component
public class User{
}
可直接替代xml中的如下配置:
<bean id="user" classs="com.bearjun.entity.User"/>
从配置文件的方式,转换成注解的方式创建对象。
- 替换接口,实现双方调用的契约性
如图,假设Consumer的invoke需要调用Provider中m1方法?但是Consumer又不知道Provider的存在?那么就需要在调用者,和被调用者之间达成一个约定,这就是契约性,这个是可以由接口来保证的!!
这个图出现了一个Contract接口,里面有method1接口方法。如果你需要调用,你只需要实现这个契约规则,只需要实现Contract这个接口,得到这个Contract接口的实现类,从而调用。
类似于这样的通过接口的方式可以实现功能调用者和被调用者之间的约定有很多,比如在开发web中,我们要写Servlet:
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
我们要实现Servlet里面的很多方法,这个Servlet接口,实际上就达成了Tomcat和我们程序员之间的约定!!
Spring注解的发展历程
Spring2.x
开始支持注解编程,提供@Component,@Service,@Scope等等,目的是为了在某些情况下,简化Xml的配置,作为Xml的有益补充。
Spring3.x
提供了更多的注解,@Configuration,@Bean等等,目的是想彻底取代Xml,基于纯注解配置。
Spring4.x
衍生出了一个跨时代的框架,Springboot,提倡使用注解进行开发!
Spring注解开发的一个问题
Spring基于注解的配置后,是否还能解耦合呢?我们知道之前的Xml是为了解耦,不需要将对象的管理,耦合在代码中,并且配置文件的方式不会被编译,达到了解耦的目的。
问题:但是这个时候,你出来了注解,是写在代码上的,那还能达到解耦的目的吗?
所以,在Spring框架上应用注解时候,如果对注解的配置内容不满意,可以通过Spring的配置文件进行覆盖的。最终你会发现,你改的还是配置文件。依旧不会存在耦合。
Spring的基础注解
这个阶段的注解,仅仅是简化XML的配置,并不能完全替代XML。
对象创建相关注解
1、@Component
作用:替换原有Spring配置文件中的
<bean>
标签
id
属性:在@Component
中提供了默认的设置方式,首字母小写(UserDAO --> userDAO)class
属性:通过反射获得的class
的内容
*** @Component细节:***
如何显式指定工厂创建对象的id值
//只需要在Component中指定名称即可
@Component("u")
Spring 配置文件覆盖注解配置内容
<!-- 只需要在applicationContext.xml中按照原始的配置bean即可 -->
<bean id="user" class="com.bearjun.entity.User">
<property name="id" value="10"/>
</bean>
***注意:id值、class值要和注解中配置的一样才会覆盖, 否则 Spring 会创建新的对象。 ***
2、@Repository、@Service、@Contoller
@Repository、@Service、@Controller都是@Component的衍生注解。
本质上这些衍生注解就是@Component,通过源码可以看见他们都使用了@Component;
它们的存在是为了:更加准确的表达一个类型的作用。
@Repository
public class UserDAO {}
@Service
public class UserService {}
@Controller
public class UserController {}
注意:Spring整合Mybatis开发过程中,不使用 @Repository
、@Component
。
3、@Scope
作用:控制简单对象创建次数。
<!--xml配置-->
<bean id="customer" class="com.bearjun.entity.Customer" scope="singleton | prototype"/>
// 创建单例对象
@Component
@Scope("singleton")
public class Customer {}
// 创建多例对象
@Component
@Scope("prototype")
public class Customer {}
注意:不添加@Scope
,Spring提供默认值singleton
。
4、@Lazy
作用:延迟创建单实例对象
<!--XML 配置-->
<bean id="account" class="com.bearjun.entity.Account" lazy="true"/>
// java配置
@Component
@Lazy
public class Account {
public Account() {
//TODO
}
}
注意:一旦使用@Lazy注解后,Spring会在使用这个对象的时候,再创建这个对象。
生命周期注解 @PostConstruct、@PreDestroy
1、@PostConstruct
初始化相关方法: @PostConstruct
- InitializingBean
-
2、@PreDestroy
销毁方法:@PreDestory
- DisposableBean
-
注意:
- 上述的两个注解并不是 Spring 提供的,由 JSR(JavaEE规范)520 提供。
- 再次验证,通过注解实现了接口的契约性。
注入相关注解
1、用户自定义类型@Autowired
- @Autowired细节
@Autowired注解基于类型进行注入 [推荐]
注入对象的类型,必须与目标成员变量类型相同或者是其子类(实现类)
@Autowired
private UserDAO userDAO;
@Autowired、@Qualifier注解联合实现基于名字进行注入。 [了解]
注入对象的id值,必须与@Qualifier注解中设置的名字相同。
@Autowired
@Qualifier("userDAOImpl")
private UserDAO userDAO;
- @Autowired注解放置位置
- 放置在对应成员变量的setter方法上,调用setter方法赋值。
- 直接放置在成员变量上,Spring通过反射直接对成员变量进行赋值。 [推荐]
- JavaEE规范中类似功能的注解
JSR250提供的@Resource(name="xxx")基于名字进行注入。
等价于@Autowired与@Qualifier联合实现的效果。
注意:@Resource注解如果名字没有配对成功,会继续按照类型进行注入。
JSR330提供的~~@Injection作用与@Autowired完全一样,一般用在EJB3.0~~中。
2、JDK类型
- @Value
1. 设置xxx.properties
id = 10
name = suns
2. Spring的工厂读取这个配置文件
<context:property-placeholder location=""/>
3. 代码中进行注入
属性 @Value("${key}")
- @propertySource
1. 设置xxx.properties
id = 10
name = suns
2. 在实体类上应用@PropertySource("classpath:/xx.properties")
3. 代码
属性 @Value("${key}")
- value注解使用细节
1、@Value注解不能应用在静态成员变量上,如果使用,获取的值为null。
2、@Value注解 + Properties这种方式,不能注入集合类型。Spring提供新的配置形式YAML(YML)(更多的用于SpringBoot中)。
注解扫描详解
<!-- 扫描当前包及其子包 -->
<context:component-scan base-package="com.xxx" />
1、排除方式:设置不扫描哪些注解
<context:component-scan base-package="com.yusael">
<context:exclude-filter type="" expression=""/>
</context:component-scan>
type可选值如下:
- assignable:排除特定的类型 不进行扫描
- annotation:排除特定的注解 不进行扫描
- aspectJ:排除对应的切入点表达式。包切入点:
com.bearjun.entity..*
,类切入点:*..User
- regex:正则表达式
- custom:自定义排除策略,框架的底层开发
注意:排除策略可以叠加使用
<context:component-scan base-package="com.xxx" >
<context:exclude-filter type="xx1" expression="xxx"/>
<context:exclude-filter type="xx2" expression="xxx"/>
</context:component-scan>
2、包含方式:设置扫描哪些注解
<context:component-scan base-package="com.xxx" use-default-filters="false">
<context:include-filter type="xx1" expression="xxx"/>
</context:component-scan>
- use-default-filters="false",作用:让spring默认的注解扫描方式失效。
- type参数
- assignable:包含特定的类型 不进行扫描
- annotation:包含特定的注解 不进行扫描
- aspectJ:包含对应的切入点表达式。包切入点:
com.bearjun.entity..*
,类切入点:*..User
- regex:正则表达式
- custom:自定义包含策略,框架的底层开发
当然:包含策略也可以叠加使用。用法同上。
对于注解开发的思考
1、注解与xml配置互通
Spring 通过注解配置,与通过xml文件进行配置是互通的。
// 通过注解配置UserDAOImpl
@Repository
public class UserDAOImpl{
//TODO
}
public class UserServiceImpl{
private UserDAO userDAO;
// set / get
}
// 通过xml配置创建userDAO对象
<bean id="userService" class="com.bearjun.service.impl.UserServiceImpl">
<property name="userDAO" ref="userDAOImpl"/>
</bean>
2、什么情况下使用注解,什么情况下使用配置文件
基础注解(@Component、@Autowired、@Value)用于程序员开发类型的配置:
-
在程序员开发的类型上,可以加入对应注解进行对象的创建。
User、UserService、UserDAO、UserAction… 这些类都很适合用注解。 -
应用其他非程序员开发的类型时(框架自带的类),需要使用
标签进行配置。
SqlSessionFactoryBean、MapperScannerConfigure等Spring创建的类,无法使用注解。
评论区