注解用在哪里:类上、方法上、属性上等等
用法:
/* 通过元注解@Target 规定自定义注解可以使用在哪些位置
* 我们使用“ElementType.静态常量"的方法来指定自定义注解具体的位置
* 而且,值可以写多个,格式:@Target({值1,值2,值3...})*/
@Target({ElementType.TYPE,ElementType.METHOD})// 注解可以加在 类上或方法上
注解的生命周期:源文件中、字节码文件中、运行中
用法:
// 通过@Retention注解标记自定义注解的生命周期
/* 通过元注解 @Retention 规定自定义注解的生命周期
* 我们使用"RetentionPolicy.静态常量"的方式来指定自定义注解的存活时间
* 注意:这里的值只能写一个:SOURCE CLASS RUNTIME 3选1*/
@Retention(RetentionPolicy.RUNTIME) // 到运行时都有效
用来定义一个注解
语法:
package cn.tedu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class TestAnnotation {
}
// 2.通过@Target注解标记自定义注解Rice可以使用的位置
/* 3. 通过元注解@Target 规定自定义注解可以使用在哪些位置
* 我们使用“ElementType.静态常量"的方法来指定自定义注解具体的位置
* 而且,值可以写多个,格式:@Target({值1,值2,值3...})*/
@Target({ElementType.TYPE, ElementType.METHOD})// 注解可以加在 类上或方法上
// 通过@Retention注解标记自定义注解Rice的生命周期
/* 4.通过元注解 @Retention 规定自定义注解的生命周期
* 我们使用"RetentionPolicy.静态常量"的方式来指定自定义注解的存活时间
* 注意:这里的值只能写一个:SOURCE CLASS RUNTIME 3选1*/
@Retention(RetentionPolicy.RUNTIME) // 到运行时都有效
//1.定义自定义注解
/*1.首先注意:注解定义的语法与java不同*/
/*2. 定义注解的格式:@interface 注解名{} */
@interface Rice {
// 5.我们可以给注解功能加强 -- 添加注解的属性
/* 6.注意:int age(); 不是方法的定义,而是给自定义注解添加了一个age属性*/
int age() default 0;
/*7.注解中还可以添加特殊属性value
* 特殊属性的定义方法与普通属性一样,要求:名字必须是value,类型不作限制*/
String value()default "lemon"; // 定义特殊属性,并给特殊属性赋予默认值
}
/* 5.注解使用时,在规定位置,@注解名 即可*/
class TestAnno{
/* 测试1:分别给TestAnno类 name属性 eat方法都添加Rice 注解
* 结论:属性上的注解报错了,
* 说明自定义注解可以加在什么位置,由@Target决定*/
// @Rice // 不能加在此位置
String name;
/*测试2:当我们给Rice注解添加了一个age属性后,@Rice注解使用时直接报错
* 结论:当注解没有定义属性时,可以直接使用
* 当注解定义了属性后,必须给属性赋值,格式:@Rice(age = 10)*/
/* 测试3:给age属性赋予默认值以后,可以直接使用@Rice注解
* 不需要给age属性赋值,因为age属性已经有了默认值*/
/* 测试4.给Rice注解添加了特殊属性value以后,也必须给属性赋值
* 只不过特殊属性value赋值时可以简写成@value*/
/* 测试5:如果特殊属性也赋予了默认值,那么就可以直接使用这个注解
* 但是如果想给注解的所有属性赋值,每条赋值语句都不能简写,包括特殊属性*/
//@Rice(age = 10)
@Rice(age = 10,value = "Apple")// 都不能简写,属性 = 属性值
public void eat(){
System.out.println("干饭不积极,思想有问题");
}
}
可以加在方法上,用来表示这是一个重写的方法
标明的方法需是 public 并且无返回值的方法
可以在spring测试时启动容器的方法上标注
可以在spring测试时关闭容器的方法上标注
@WebFilter(“/a/*”):表示以那种方式请求时可以匹配,*****代表通配
@WebFilter("/a/*")
public class Filter1 implements Filter {
// 销毁
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("过滤器开始执行~~");
chain.doFilter(req, resp); // 放行,解除阻塞状态
}
// 初始化
public void init(FilterConfig config) throws ServletException {
}
}
将当前类标识为配置类,配置类也是一个bean,用于创建其他bean
将多个配置类结合起来,把相关的bean放在一起。防止一个配置类过大,通常将应用程序和基础架构分离
用在配置类中的方法上,将方法的返回值交给Spring容器管理
获取bean时有三种方案
User user1 = (User) a.getBean("user");
User user2 = a.getBean("user", User.class);
User user = a.getBean(User.class);
用在配置类中,根据路径扫描子孙包,使@Component注解有效,和@component配合使用
// 准备一个配置类
@Configuration
@ComponentScan("com.jt")
// 当spring 容器启动时,根据指定的包路径,扫描其子孙包
public class SpringConfig { }
@Scope(“prototype”) :多例模式需要配置
@Scope(“singleton”) :单例模式不配置的话默认的是单例模式
@Scope(“session”) : 每个用户会话创建新的实例(仅限Web环境)
@Scope(“request”) : 每个请求创建一个实例
使用在@Bean 标注的方法上
懒加载(在使用时才加载),单例模式默认为立即加载(在创建容器时就创建对象) 在多例模式中不管加不加都为懒加载
应用场景1:服务器启动时,如果加载太多资源必然会慢,所以将一些不重要的资源设置为懒加载
应用场景2:有时用户会需要一些链接,而这些链接的创建需要很长的时间,这时可以使用懒加载
@Configuration // 将当前类标识为配置类
@ComponentScan("com.jt")
public class SpringConfig {
@Bean // 将方法的返回值交给Spring容器管理
// @Scope("singleton") // 默认的单例模式
@Scope("prototype") // 多例模式
public User user(){
return new User();
}
}
将当前类交给spring容器管理,对象创建是由spring通过反射机制自动创建的
当不能直接创建对象时使用工厂模式:例如抽象类,封装第三方框架时也常用到
用法:
@Component(“指定容器中key的值”)
在spring容器中的map中 key 为 calendar,value 为 getObject()返回的对象
/**
*
* 在spring容器中的map中 key 为 calendar,value 为 getObject()返回的对象
*
* 该功能应用的场景:
* 1.某些对象不能直接被实例化的情况,如抽象类
* 2.整合第三方框架对象时,经常用到
*/
@Component("calendar") // 在spring容器中的map中 key 为 calendar
public class CalendarFactory implements FactoryBean<Calendar> {
@Override
public Calendar getObject() throws Exception {
return Calendar.getInstance();
}
@Override
public Class<?> getObjectType() {
// 固定写法
return Calendar.class;
}
}
@Autowired 默认的依赖是必须的即当依赖不存在是会报错,将属性 required 设为false (@Autowired(required=false))时,当依赖存在时会注入,不存在时不会报错
@Autowired // 如果这是唯一的构造方法,该注解是可选的
public TransferServiceImpl(AccountRepository repo) {
this.accountRepository = repo;
}
private AccountRepository accountRepository
@Autowired
public void setAccountRepository(AccountRepository repo) {
this.accountRepository = repo;
}
@Autowired
private AccountRepository accountRepository;
构造方法 | Setter |
---|---|
强依赖性 | 可能的循环依赖项 |
依赖项可以是不变的 | 依赖项是可变的 |
简洁(一次性传递多个参数) | 多参数时,比较冗余 |
自动继承 |
需要和@Autowired配合使用
功能等同于@Autowired + @Qualifier 虽然方便但是不推荐使用,因为其不是spring框架提供的,担心在以后的兼容性问题,仅支持Setter和字段注入
@Component
public class User {
/* 将接口的实现类自动注入*/
// @Resource(name = "cat") // 功能等同于@Autowired + @Qualifier("cat")
@Autowired
@Qualifier("cat") // 该注解不能单独使用,必须配合Autowired 使用,根据key进行注入
private Pet pet;//
public void say() {
pet.hello();
}
被添加以下两个注解的方法 是任意可见性的,必须没参数,返回值类型必须是void
在容器对象创建后立即调用
仅当应用程序正常关闭时会调用,程序意外终止或强制终止时不会调用
一般用来执行关流操作,当有@Scope(“prototype”)时,将无效,
当有@Scope(“prototype”)时,每次都会创建一个新的对象,spring为了避免内存泄漏,不会缓存对象的引用,所以spring关闭时就无法处理对象的销毁方法
@Value注解 可以直接为基本类型和String类型(集合(几乎不用))赋值
@Value("${daily.limit}")
int maxTransfersPerDay;
@Value("#{environment['daily.limit']}")
int maxTransfersPerDay;
以上两种方式是等效的
为了降低@value 赋值的耦合性,所以需@PropertySource 和 .properties配置文件 配合使用文件在resources目录下
****.properties配置文件中的key和值用“=”表示(key=value)
可用资源前缀:classpath: ,file: ,http: @PropertySource("classpath:/com/organization/config/app.properties") @PropertySource("file:config/local.properties")
也可用@value来访问properties
@Configuration
public class DbConfig {
@Bean
public DataSource dataSource(
@Value("${db.driver}") String driver,
@Value("${db.url}") String url,
@Value("${db.user}") String user,
@Value("${db.password}") String password) {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(password);
return ds;
@Repository // 功能等同于 @component 用于持久层
// 指定配置文件的路径 classpath:/ 是固定写法 encoding 是解决中文乱码
@PropertySource(value = "classpath:/user.properties",encoding = "utf-8")
public class UserManperImpl implements UserManper{
// 根据key的值取到spring容器中value的值
// 从配置文件中取变量的值 ${} 是固定写法 是spel(springel)表达式
@Value("${name}")
private String name;
@Override
public void addUser() {
System.out.println("添加用户"+name);
}
在配置类中使用,表示开启AOP 默认使用的是JDK动态代理
将proxyTargetClass的属性改为ture(默认的是false)就是使用cglib动态代理@EnableAspectJAutoProxy(proxyTargetClass = true)
@Configuration
@ComponentScan("com.jt")
@EnableAspectJAutoProxy // 开启AOP
public class SpringConfig { }
如果目标对象满足切入点表达式,spring 会自动创建代理对象
根据bean的id进行匹配 @Pointcut("bean(userServiceImpl)")
按照类型进行匹配
语法:
1. @Pointcut("within(com.jt.service.UserServiceImpl)")
只拦截UserServiceImpl的类
2. @Pointcut("within(com.jt.service.*)")
拦截com.jt.service下的一级的类.
3. @Pointcut("within(com.jt.service..*)")
拦截com.jt.service下所有包下的所有类
4. @Pointcut("within(com.*.service..*)")
拦截com.任意包.service下所有包下的所有类
按照方法名和参数进行匹配
用法:
语法: @Pointcut("execution(返回值类型 包名.类名.方法名(参数列表))")
1. 按照类型方法匹配
@Pointcut("execution(* com.jt.service.UserServiceImpl.addUser())")
2. 要求返回值任意, com.jt.service包下的所有的子孙类中的任意方法的任意参数要求拦截.
@Pointcut("execution(* com.jt.service..*.*(..))")
3. 要求返回值任意, com.jt.service包下的所有的子孙类中的add开头的方法并且参数1个是int类型 进行拦截
@Pointcut("execution(* com.jt.service..*.add*(int))")
可以使用自定义注解来进行标识方法,用来匹配目标方法
@Pointcut(“@annotation(com.jt.anno.Hxwang)”)
execution表达式和注解表达式比较常用
切面概述: 与 pointcut 结合的 advice 的囊括
@Component // 将给类叫给Spring容器管理
@Aspect// 标识该类是一个切面
public class SpringAop {
/**
* AOP 利用动态代理扩展目标方法
* 切面 = 切入点表达式 + 通知方法
* 切入点表达式:如果对象满足切入点表达式的判断,则spring自动为其创建代理对象
* 通知方法:目标方法进行扩展的封装方法。
* 目标对象的bean的ID:userServiceImpl
* 切入点表达式:
* 1.bean("bean的id")
*/
@Pointcut("bean(userServiceImpl)")
public void pointcut(){
}
在目标方法执行之前执行,如果前置方法执行时异常则目标方法不会执行,参数是切入式表达式的方法一般是用pointcut做方法名,也可以将切入点表达式直接传入@Around("@annotation(com.jt.anno.Hxwang)")
@Before("pointcut()")
public void before(JoinPoint joinPoint){//连接点:获取方法中的数据
Class targetClass = joinPoint.getTarget().getClass();
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getSignature().getDeclaringTypeName();
Object[] objs = joinPoint.getArgs();
System.out.println("我是前置通知!!!!");
System.out.println("类型:"+ targetClass);
System.out.println("方法名称:"+methodName);
System.out.println("类的名称:"+className);
System.out.println("方法中携带的参数:"+ Arrays.toString(objs));
在目标方法执行之后执行,可以通过returning属性获取方法的返回值。
如果目标方法执行异常,则此方法不执行
可以用来记录目标方法的返回值但是不能修改
//2.后置通知: 在目标方法执行之后执行
// 通过returning = "result"属性,获取目标方法的返回值,当作参数传递给result
@AfterReturning(value = "pointcut()",returning = "result")
public void afterReturn(Object result){
System.out.println("我是后置通知!!!!");
System.out.println("用户的返回值为:"+result);
}
在目标方法报异常时执行 ,不能阻止异常传播
在目标方法后都要执行(不管目标方法是否异常)
以上注解可以记录程序执行的各个过程,为日志提供记录
在目标方法前后都要执行,控制目标方法,其权重大于以上注解,最先执行并且最后执行 @around环绕通知 可以控制目标方法是否执行. 环绕通知可以控制业务流转的过程!!!
例子:
@Around("pointcut()")
// ProceedingJoinPoint 只能用在环绕通知里
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前执行");
// 底层调用动态代理的invoke方法,执行目标方法
Object object = joinPoint.proceed();
System.out.println("环绕后执行");
return object;
}
如果返回值是字符串将本身返回(用在类和方法上,可以用@RestContorller 代替)
// @RequestMapping(value = "/saveUser",method = RequestMethod.POST)
@PostMapping("/saveUser")// 与上诉功能一样 ,接受固定类型的请求
public String saveUser(@RequestBody User user){// @RequestBody 将JOSN对象转换为user对象(只有在post请求中使用)
System.out.println(user);
return "新增数据成功";
}
功能等同于 @Controller + @ResponseBody
可以用在类和方法上
可以接收任意方式的请求,不安全
用法:
@RestController // 功能等同于 @Controller + @ResponseBody
@RequestMapping("/acb")
public class RestUserController {
// url = http://localhost:8080/acd/findJson
@RequestMapping("/findJson")
public User findUser(User user){
return user;
}
}
当 put 请求类型 在地址栏拼接 restful 风格的参数时,用对象接 不用加@RequestBody
@PutMapping("/updateUser")
public String updateUser(@RequestBody User user){
System.out.println(user);
return "修改成功";
}
和 @RequestMapping 的用法一样
该注解的作用用来加载springBoot-start-xxx的启动项.当主启动类执行时,则会开始加载启动项中的配置.则功能加载成功
pojo 需要实现序列化接口 Serializable
用在 pojo 文件中的对象类中可以解决代码冗余问题(来自 lombok 插件 需要安装插件或pom文件中配置)
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
来自 lombok 插件
一般用与设置默认值
Mybatis只能是单值传参,@Param可以代替集合传参的方式
List<User> findByAnno(@Param("minAge") int minAge, @Param("maxAge") int maxAge);
使用@mapper后,不需要在spring配置中设置扫描地址,通过mapper.xml里面的namespace属性对应相关的mapper类,spring将动态的生成Bean后注入到ServiceImpl中。
@RestControllerAdvice
// 全局异常处理机制,只需拦截 controller 层
public class SystemException {
@ExceptionHandler(RuntimeException.class) // 指定异常的类型进行拦截
public SysResult exception(Exception e){
e.printStackTrace(); // 打印异常
return SysResult.fail(); // 给前端状态码
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jt.mapper.UserMapper">
<select id="findAll" resultType="com.jt.pojo.User">
select * from demo_user
select>
<select id="findById" resultType="com.jt.pojo.User">
select * from demo_user where id = #{id}
select>
<select id="findByNA" resultType="com.jt.pojo.User">
select * from demo_user where
name = #{name} and age = #{age}
select>
<select id="findByMap" resultType="com.jt.pojo.User">
#{minAge} and age < #{maxAge}
]]>
select>
<select id="findByAnno" resultType="User">
#{minAge} and age < #{maxAge}]]>
select>
<select id="findByLike" resultType="User">
select <include refid="sql1"/> from demo_user where name like #{name}
select>
<sql id="sql1">
id,name,age,sex
sql>
<select id="findByArray" resultType="User">
select <include refid="sql1"/> from demo_user where id in (
<foreach collection="array" item="id" separator=",">
#{id}
foreach>
)
select>
mapper>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jt.mapper.EmpMapper">
<select id="findAll" resultMap="emRm">
SELECT <include refid="sql"/>
FROM emp,dept
WHERE emp.dept_id = dept.dept_id
select>
<resultMap id="emRm" type="Emp" autoMapping="true">
<id column="id" property="id"/>
<association property="dept" javaType="Dept" autoMapping="true">
<id column="dept_id" property="deptId"/>
association>
resultMap>
<sql id="sql">
emp.id,dept.dept_id,emp.age,emp.name,dept.dept_name
sql>
mapper>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jt.mapper.DeptMapper">
<select id="findAll" resultMap="dept">
select dept.dept_name,emp.*
from dept,emp
where dept.dept_id = emp.dept_id
select>
<resultMap id="dept" type="Dept" autoMapping="true">
<id column="dept_id" property="deptId"/>
<collection property="emps" ofType="Emp" autoMapping="true">
<id column="id" property="id"/>
collection>
resultMap>
mapper>
其value属性值有两个层面的含义:第一个含义就是要你要的远程服务名,第二个含义就是当前bean的名字
@Documnet注解对索引的参数进行设置。
下面代码中,把 students 索引的分片数设置为3,副本数设置为2。
在 Elasticsearch 中创建文档时,使用 @Id 注解的字段作为文档的 _id 值
通过 @Field 注解设置字段的数据类型和其他属性。
文本类型 text 和 keyword
text 类型会进行分词。
keyword 不会分词。