Spring中常用注解
组件注解
@Component("xxx")
指定某个类是容器的bean,@Component(value="xx")相当于
@Component
用于标注一个普通的类
@Controller
用于标注一个控制器类
@Service
用于标注业务逻辑类
@Repository
用于标注DAO数据访问类
现在这几个注解没有什么区别,尽量根据类的不同功能选择合适的注解。注解用于修饰类,当不写value属性值时,默认值为类名首字母小写。
组件扫描注解
@ComponentScan
bean相关注解
@Bean
@Scope("prototype")
该注解和@Component
这一类注解联合使用,用于标记该类的作用域,默认为singleton,也可以和bean一起使用,此时@scope修饰一个方法
@DependsOn({"aa","bb"})
该注解也是配合@Component
这类注解使用,用于强制初始化其他bean
@Lazy(true)
指定bean是否延时初始化,相当于<bean id="xx" lazy-init="">
,默认false。@Lazy可以和@Component这一类注解联合使用修饰类,也可以和@Bean一起使用修饰方法
@DepondsOn("other")
@Lazy(true)
@Controller
@Scope("prototype")
public class UserAction{
...............
}
上面的代码指定,初始化bean “userAction"之前需要先初始化“aa”和“bb”两个bean,但是使用了@Lazy(true)所以spring容器初始化时不会初始化"userAction” bean。
bean(singlton作用域)的生命周期的行为注解
@PostConstruct
构造器之后调用相当于
@PreDestroy
容器销毁之前bean调用的方法,相当于
两者修饰方法来管理容器中spring生命周期行为.
自动装配
@Resource(name="xxx")
可以修饰变量成员也可以修饰成员方法,当修饰成员变量时可以不写set方法,此时spring会直接使用jee规范的Field注入
两个比较重要的属性,name和type
- 如果指定了name和type,则从Spring容器中找到唯一匹配的bean进行装配,找不到则抛出异常;
- 如果指定了name,则从spring容器查找名称(id)匹配的bean进行装配,找不到则抛出异常;
- 如果指定了type,则从spring容器中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常;
- 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配
如果没有写name属性值时
- 修饰成员变量,此时name为成员变量名称
- 修饰set方法,此时name 为set方法的去掉set后首字母小写得到的字符串
@Autowired(requird=false)
可以修饰构造器,成员变量,set方法,普通方法,默认使用byType方式自动装配,required标记该类型的bean是否是必须的,默认为必须存在(true)
- required=true(默认),为true时,从spring容器查找和指定类型匹配的bean,匹配不到或匹配多个则抛出异常
- 使用@Qualifier("xx"),则会从spring容器中匹配类型和id一直的bean,匹配不到抛出异常
@Autowired会根据修饰的成员选取不同的类型
- 修饰成员变量。该类型为成员变量类型
- 修饰方法,构造器。注入类型为参数的数据类型,当然可以有多个参数
@Qualifier
//service层,业务逻辑
@Service
public class UserService{
@Resource(name="userDao")
private UserDao userDao;
//@Autowired
//@Qualifier("userDao")
//private IUserDao userDao;
//相对来说使用`@Resource`更简单一些
.......实际业务.............
}
//dao层,持久化
@Repository
@Lazy(true)
@Scope("singleton")
public class UserDao implements InitializingBean,DisposableBean{
public UserDao() {
System.out.println("constructor...................");
}
public List<User> listUsers(){
System.out.println("查询所有用户");
}
@PostConstruct
public void postConstructor() {
System.out.println("post_constructor.................");
}
//覆盖InitializingBean接口方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("after_properties_set..............");
}
@PreDestroy
public void after() {
System.out.println("pre_destroty.................");
}
//重写DisposableBean方法
@Override
public void destroy() throws Exception {
System.out.println("destry_method.............");
}
}
//测试类
public class TestAnnotation{
@Test
public void test1(){
ClassPathXmlApplicationContext application=new ClassPathXmlApplicationContext("applicationContext.xml");
//配置文件里只有一行就是开启自动扫描” <context:component-scan base-package="com" /> “
System.out.println("-------------------");
System.out.println(application.getBean("userDao"));
}
}
AOP相关注解
该注解是AspectJ中的注解,并不是spring提供的,所以还需要导入aspectjweaver.jar,aspectjrt.jar,除此之外还需要依赖aopalliance.jar
@Aspect
修饰java类,指定该类为切面类,spring不会对该bean做增强处理
@Before("pointcut_expresisson")
修饰方法,before增强处理
@AfterReturning
修饰方法,afterreturning增强处理,目标方法正常结束后做增强处理
常用属性
- pointcut/value:定义切入点
- returning:指定一个参数名,用于接受目标方法正常结束时返回的值。在增强方法中定义同名的参数
@AfterThrowing
修饰方法,afterthrowing增强处理。当目标程序方法抛出 异常或者异常无法捕获时,做增强处理。
常用属性
- pointcut/value :指定切入点表达式
- throwing:指定一个形参,在增强方法中定义同名形参,用于访问目标方法抛出的异常
@After
修饰方法 ,after增强处理。无论方法是否正常结束,都会调用该增强处理(@After= @AfterReturning+@AfterThrowing)。一般用于释放资源。
有一个value属性,用于指定切入点表达式。
@Arround
修饰方法, around增强处理。该处理可以目标方法执行之前和执行之后织入增强处理,可以看作时@Before和@AfterReturning的总和。
有一个value属性,指定切入点表达式。
Around增强处理通常需要在线程安全的环境下使用,如果@Before和@AfterReturning可以处理就没必要使用@After Returning
当定义一个Around增前处理时,增强方法第一形参需要时ProceedingJoinPoint类型。ProceedingJoin Point有一个Object proceed()方法,用于执行目标方法,返回对象当然也可以为目标方法传递数组参数。
//切面类
@Aspect
public class UserAdvice{
@Pointcut("execution(* com.User*.*(..))")
public void userAdvice(){}
@Before(value="userAdvice()")
public void authority(){
System.out.println("权限检查。。。");
}
@AfterReturning(pointcut="userAdvice")
public void log(){
System.out.println("写入日志。。。");
}
@After("userAdvice()")
public void release(){
System.out.println("资源释放。。。");
}
@Around("userAdvice()")
public void arround(ProceedingJoinPoint joinPoint){
System.out.println("开启事务。。。");
joinPoint.proceed(jointPoint.getArgs());
System.out.println("关闭事务。。。");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="com" /> <!--自动扫描-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy><!--开启@AspectJ支持-->
</beans>
//测试类
public class TestAnnotation{
@Test
public void test1(){
ClassPathXmlApplicationContext application=new ClassPathXmlApplicationContext("applicationContext.xml");
//配置文件里只有一行就是开启自动扫描” <context:component-scan base-package="com" /> “
IUserDao userDao = application.getBean("userDao",UserDao.class);
userDao.listUsers();
}
}
输出结果
constructor...................
post_constructor.................
after_properties_set..............
开启事务。。。
权限检查。。。
System.out.println("查询所有用户");
关闭事务。。。
资源释放。。。
写入日志。。。
pre_destroty.................
destry.............
pre_destroty.................
destry.............
spring aop采用和AspectJ相同的优先顺序织入,进入连接连接点时,具有最高优先级的增强处理先被织入,在退出优先级时最高优先级的增强处理先被执行。
@Pointcut
修饰方法,定义一个切入点,用于被其他增强调用。
切入点的定义和普通定义类似
@Pointcut("execution(* user*(..))")
//使用一个返回值为void,空方法体的方法命名切入点。
//public 为修饰符,跟方法的修饰符一致,public 可以在其他切面类中使用该切点,default在同一个包下的切面类中使用该切点
//返回值必须为void , 方法名就是定义的切点名称
public void userAdvice(){}
@Order
当不同的切面中的两个增强处理需要在同一个连接点被织入时,spring aop可以指定不同切面类的增强处理优先级。
有一个value属性,指定一个int值,属性值越小优先级越高。
切入点表达式
execution表达式格式
execution(modifiers-pattern? return-type-pattern declaring-type-pattern? method-name(param-pattern) throws-pattern?)
注:?表示出现一次或零次
- modifers-pattern:指定方法的修饰符,支持通配符,可以省略
- return-type-pattern ;方法返回值类型,必写可以使用通配符,表示所有返回值类型
- declaring-type-pattern:全限定类名。可以省略,表示所有类。可以使用通配符com.example.dao.User,表示 匹配com.example.dao包下,所有以User开头的类
- method-name:指定方法名,必写。可以使用通配符*,表示所有方法。
- param-pattern:方法参数,必写。可以使用通配符* ,表示任意一个参数类型。也可以使用通配符…,表示零个或多个任意类型的参数。(*,String),表示第一个参数类型任意,第二个必须为String类型。
- throws-pattern:方法抛出异常,可以省略
within1. 匹配指定类下的所有方法。 2. 匹配执行包下所有类下的所有方法
@annotation
用于匹配当前执行方法持有指定注解的方法;
@within
用于匹配指定注解修饰类下的所有方法
AOP配置
@Component
@EnableAspectJAutoProxy
@Aspect
public class ControllerLog {
@Pointcut(value="execution(* com.example.controller.*.*(..))")
public void addLog(){}
//任意类
@Pointcut(value="within(com.example.controller.*)")
public void withinMethod(){}
@Pointcut(value="@within(com.example.annotation.ParamAnnotation)")
public void withinAnnotation(){}
@Pointcut(value="@annotation(com.example.annotation.ParamAnnotation)")
public void annotationAnnotation(){}
@Before(value = "addLog()")
public void execute(JoinPoint joinPoint){
System.out.println("增强处理。。。。。。。。。。。。");
Signature signature = joinPoint.getSignature();
System.out.println(signature.getName());
System.out.println(signature.getDeclaringTypeName());
System.out.println("增强处理结束!!");
}
@Before(value = "withinMethod()")
public void within(JoinPoint joinPoint){
System.out.println(" withinMethod 增强处理。。。。。。。。。。。。");
System.out.println(" withinMethod 增强处理结束!!");
}
@Before(value = "withinAnnotation()")
public void executeWithAnnotation(JoinPoint joinPoint){
System.out.println("withinAnnotation 增强处理。。。。。。。。。。。。");
System.out.println("withinAnnotation 增强处理结束!!");
}
@Before(value = "annotationAnnotation()")
public void annotationAnnotation(JoinPoint joinPoint){
System.out.println("annotationAnnotation 增强处理。。。。。。。。。。。。");
System.out.println("annotationAnnotation 增强处理结束!!");
}
}
接口
@Controller
@ParamAnnotation
public class UserController {
@Autowired
private IUserDao userDao;
@ParamAnnotation
@RequestMapping("/users")
@ResponseBody
public Object searchUsers(Model model){
System.out.println("---------------");
List<User> users=userDao.searchUsers();
return users;
}
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "hello world";
}
}
测试结果
1.调用/users
annotationAnnotation 增强处理。。。。。。。。。。。。
annotationAnnotation 增强处理结束!!
增强处理。。。。。。。。。。。。
searchUsers
com.example.controller.UserController
增强处理结束!!
withinAnnotation 增强处理。。。。。。。。。。。。
withinAnnotation 增强处理结束!!
withinMethod 增强处理。。。。。。。。。。。。
withinMethod 增强处理结束!!
-----searchUses----------
2.调用/hello
增强处理。。。。。。。。。。。。
hello
com.example.controller.UserController
增强处理结束!!
withinAnnotation 增强处理。。。。。。。。。。。。
withinAnnotation 增强处理结束!!
withinMethod 增强处理。。。。。。。。。。。。
withinMethod 增强处理结束!!
Java配置类相关注解
@Configuration
作用于类上,相当于一个xml配置文件;
@Import({xxxx.class})
修饰java类,用于向当前配置类导入其他java配置类
@ImportResource("classpath:aaa.xml")
修饰Java类,用于向当前注解类导入xml配置文件
上面两个都是用于配置的导入相当于<import resource="">
元素
@Value("${expression}")
修饰成员变量,或者方法构造器的参数,常用于注入文件中的值,不能对static属性注入
@ConfigurationProperties
用于从主属性文件中获取值 application.properties 或者 application.yml。当然了 如果在属性文件中引入其他配置文件,也可以获取到属性值。
- value | prefix 两者互为别名。指定前缀,默认为""
- ignoreUnknownFields:默认为true。是否忽略未知字段,当实体中的字段在配置文件中不存在时,是忽略还是抛出异常
- ignoreInvalidFields: 默认false。 是否忽略不合法的字段,此处的不合法是指类型不合适,配置文件中存在改配置但是无法转化为指定的字段类型。
ConfigurationProperties 可以配置前缀,然后会根据实体的变量名拼接前缀,去配置文件中查询配置
# 开发环境的配置文件 application-dev.properties
# 通常会配置三套, 生产,测试,本地
# 将通用部分配置存放在 application.yml,譬如 数据库连接等信息存放在application-xxx.yml中。这样不用每次都要繁琐的修改。
spring.profiles.active=dev
# 配置mybatis
mybatis.configuration.mapperLocations=classpath:mybatis/mapper/*.xml
mybatis.configuration.typeAliasPackage=com.example.domain
mybatis.configuration.configLocation=classpath:mybatis/mybatis-config.xml
@Component
@ConfigurationProperties(prefix="mybatis.configuration")
public class MybatisProperties {
private String configLocation ; //配置文件的路径等价于 @Value("mybatis.configuration.configLocation")
private String mapperLocations; //配置Mapper映射文件的路径
private String typeAliasPackage; //别名的实体路径
public String getConfigLocation() {
return configLocation;
}
public void setConfigLocation(String configLocation) {
this.configLocation = configLocation;
}
public String getMapperLocations() {
return mapperLocations;
}
public void setMapperLocations(String mapperLocations) {
this.mapperLocations = mapperLocations;
}
public String getTypeAliasPackage() {
return typeAliasPackage;
}
public void setTypeAliasPackage(String typeAliasPackage) {
this.typeAliasPackage = typeAliasPackage;
}
}
@Bean (name="xxx")
作用于方法上,相当于xml配置中的
常用的属性
name:bean id 。name可以省略,省略时name值为方法名。
autowire: 是否自动注入,默认Autowire.NO
initMethod:bean的初始化方法。在依赖注入之后执行
destroyMethod: spring容器关闭时bean调用的方法
当然@Bean还可以配合@Scope指定bean的作用域
@Configuration //通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
@ComponentScan(basePackages = "cn.springboot.javaconfig") //配置扫描包
public class SpringConfig {//SpringConfig 用于实例化Spring容器
@Bean // 通过该注解来表明是一个Bean对象,相当于xml中的<bean>
public UserDAO getUserDAO(){
return new UserDAO(); // 直接new对象做演示
}
}
@Configuration
public class UserConfiguration{
@Bean(name="userDao")
public UserDao userDao(){
return new UserDao();
}
@Bean
public UserService userService(){
UserService service=new UserService();
service.setUserDao(userDAo());
return service;
}
}
@PropertySoure(value="classpath:jdbc.properties")
用于加载配置文件,但和Configurationproperties有些不同
使用该注解加载的配置文件就是相对独立文件。例如 :数据源的配置信息我们可以配置在application.yml 中,也可以将该部分内容单独放在一个文件里(jdbc.properties)。
存在的属性:
- ignoreResourceNotFound: 当资源文件找不到的时候是否会忽略该配置,而不是抛出错误。一般用于可选项
- encoding : 资源文件使用什么编码方式
#数据源配置
spring.datasource.url=xxxxxxxx
spring.datasource.username=xxxx
..............................
@Configuration
@PropertySource(value="classpath:jdbc.properties")
public class DatasourceConfig {
private Logger logger = LoggerFactory.getLogger(DatasourceConfig.class);
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.type}")
private String dbType;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.maxWait}")
private int maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;
@Value("${spring.datasource.filters}")
private String filters;
@Value("${spring.datasource.druidLoginName}")
private String druidLoginName;
@Value("${spring.datasource.druidPassword}")
private String druidPassword;
@Bean(name="dataSource",destroyMethod = "close", initMethod="init")
@Primary
public DataSource dataSource(){
DruidDataSource datasource = new DruidDataSource();
try {
datasource.setUrl(this.dbUrl);
datasource.setDbType(dbType);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("druid configuration initialization filter", e);
}
return datasource;
}
}
SpringMVC相关注解
@Controller
标记一个类为SpringMVC Controller 对象
@RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
@Resource和@Autowired
@PathVariable
@CookieValue
@RequestParam
@SessionAttributes
@ModelAttribute
@RequestBody
从Reuqest请求体中获取内容,绑定到方法的指定参数上。 请求体内容使用HttpMessageConverter 转化方法参数类型。
SpringMVC 给用户对参数的处理提供了很大支配权。 我们可以使用 RequestBodyAdvice 来实现对参数进行拦截处理。
注意
RequestBodyAdvice : 针对所有以@RequestBody的参数做处理
自定义的处理对象类上必须得加上@ControllerAdvice注解!
利用此功能我们就可以对参数做加密处理。定义一个注解。用来控制参数是否加密
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SecurityParameter {
/**
* 入参是否解密,默认解密
*/
boolean inDecode() default true;
/**
* 出参是否加密,默认加密
*/
boolean outEncode() default true;
}
@ResponseBody
将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;