我们以一个简单的小例子来理解Spring注解开发中常用的注解类型及其作用:
先理解三大核心思想:
1.控制反转ioc
简单来说就是用一个很大的容器来管理所有对象(包括数据层dao、业务层service等等),这样我们创建对象时就可以直接从容器获取,降低代码耦合度。
2.依赖注入
业务层使用数据层对象时、传递基本数据类型或引用数据类型时都不能把代码写死,这时需要依赖注入为我们绑定对象关系或传递数据。
3.AOP面向切面编程
把一些方法中的共性方法抽离为一个通知类下的通知方法,每个方法都可以通过一个切入点与通知连接来执行通知,这就在不改变代码设计的基础上增强了代码功能。
注解开发:简言之就是配置类+注解的方式来代替xml开发
准备工作:pom导入相关依赖坐标---缺一不可
<!--解决发行版本错误的问题-->
<build>
<plugins>
<!--jdk编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--导入spring框架的坐标依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--导入阿里巴巴的druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<!--导入mybatis依赖,需要刷新一下,导入该依赖就可以使用该持久层框架-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--导入mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--导入junit,测试框架-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!--导入spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--导入spring操作数据库坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--导入mybatis整合spring坐标依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!--导入切面相关包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.3</version>
</dependency>
</dependencies>
1.创建Config配置类
(1)spring核心配置类,代表使用spring框架开发
1.@Configuration
代表spring核心配置文件xml里的基本东西都不用写了
2.@ComponentScan({"service","aop","dao"})
代表包扫描,以数组形式扫描多个包,扫描完成后就可以用spring中的bean来管理这些包里的对象了
3.@PropertySource
用来加载一些properties文件,也是代替了xml,因为它只能写死
这里注意properties文件存放在resources下,可以通过其他配置类中注解+${]来获取文件中的值
jdbc.properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=JDBC:mysql://localhost:3306/teststudy?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
jdbc.username=root
jdbc.password=0716
JdbcConfig:
import javax.sql.DataSource;
//用于数据库连接和第三方数据源管理
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds=new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
}
4.@Import
用来导入其他的配置类
例如MybatisConfig:
public class MybatisConfig {
//加载sqlsessionfactory对象
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb=new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("pojo");
ssfb.setDataSource(dataSource);
return ssfb;
}
@Bean
//加载mapper映射
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc=new MapperScannerConfigurer();
msc.setBasePackage("dao");
return msc;
}
}
注意这里仍使用mapper代理思想,但是不再使用xml映射文件,而是利用配置类做映射
这里插入小tips:德鲁一数据源(我们可以理解成它的作用就是为了提高操作数据库时候的性能,不得不使用数据库连接池)
注意导入配置类需要用反射
5.@EnableAspectJAutoProxy
表示识别aop包后以切面思想处理它
2.dao包
直接创建mapper接口使用注解写sql语句
public interface depDao {
//使用注解开发来写数据底层方法
//查询所有,返回值类型+方法名,接口方法的书写格式
//无需传参,返回列表数据类型
//注意注解标红肯定是有什么坐标没导进去
@Select("select * from dep")
List<dep> findAll();
}
不创建xml后需创建实现类和数据库表对应的pojo
@Repository
public class baiduimpl implements paidu{
@Override
public boolean read(String url, String password) {
//模拟校验,使用equals方法
boolean flag = password.equals("zs025563");
return flag;
}
}
6.@Repository
代表数据层注解,有了它就意味着spring可以用bean来管理这个实现类的对象了
3.service包
写对应的接口和实现类
@Service
public class depservice implements ds{
//该注解可以使dao层对象自动装配,实现依赖注入,也就是关系绑定
@Autowired
private depDao dep;
public List<dep> selectAll(){
//调用数据层对象方法
List<pojo.dep> all = dep.findAll();
return all;
}
}
7.@Service
表示为业务层注解,与6同意,@controller表示表现层注解
8.@Autowired
表示自动装配,可以绑定数据层和业务层的对象关系,也就是依赖注入
4.web包
实现查询所有功能
//使用纯注解方式开发的运行,加载配置类而不是配置文件
public class findall1 {
public static void main(String[] args) {
//加载spring配置类
ApplicationContext c=new AnnotationConfigApplicationContext(SpringConfig.class);
//获取业务层对象
ds depservice =c.getBean(ds.class);
//调用对象方法
List<dep> deps = depservice.selectAll();
System.out.println(deps);
}
}
这里无需注解
但注意:通用做法就是加载核心配置类和使用容器获取对象
不加载核心配置文件会发生报错
获取对象一般采用按名称或按类型,注意按名称要在实体类注解声明时加上名称
5.Aop包
一个通知类的示例:查看所有业务层方法执行效率
//用该通知类描述共性方法:测试业务层接口方法执行效率
//打开spring配置识别注解
@Component
//打开切面类识别注解
//当这个注解无法使用时就要去看一看是不是对应坐标没有导进去
@Aspect
public class RunAdvice {
//创建切入点
//用来匹配业务层所有方法
@Pointcut("execution(* service.*service.*(..))")
//第一个*代表所有返回值类型;第二个*代表所有业务层实现类;第三个*代表实现类下的所有方法;..代表所有传参
private void servicept(){
}
//环绕通知,传入切入点
@Around("RunAdvice.servicept()")
public void runservice(ProceedingJoinPoint p) throws Throwable {
//获取签名
Signature signature = p.getSignature();
//获取类名
String declaringTypeName = signature.getDeclaringTypeName();
//获取方法名
String name = signature.getName();
long start=System.currentTimeMillis();
//执行万次
for(int i=0;i<10000;i++) {
p.proceed();
}
long end=System.currentTimeMillis();
System.out.println(declaringTypeName+"."+name+"方法万次执行时间为----"+(end-start)+"ms");
}
}
9.@Component
代表可以用spring进行识别,其地位作用等同于@controller\@repository\@service那三个注解
10.@Aspect
代表可以使用切面思想处理该配置类
注意该注解需要单独导入相应坐标依赖
11.@Pointcut
切入点注解,后面所跟定位要定位于对应层下的接口方法或实体类方法
12.@Around
环绕通知配置,注意传参,可以使源程序在被环绕时也可以正常调用