一、Spring
1.1 Bean 开发(注解)
1.1.1 注解开发定义 Bean
1.1.2 小结
1.2 Bean 管理(注解)
1.2.1 Bean 作用范围
@Scope("singleton")单例模式@Scope("prototype")多例模式
1.2.2 Bean 生命周期
@PostConstruct构造函数之后@PreDestory销毁之前
1.3 Bean 依赖注入(注解)
1.3.1 Bean 自动装配注入
- 使用
@Autowired注解开始自动装配模式(按类型)
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
public void save (){
System.out.println("book service save ...");
bookDao.save();
}
}
- 注意:自动装配
基于反射创建对象并暴力反射对应属性为私有属性初始化数据,无需提供setter方法 - 注意:自动装配建议使用无参构造方法创建对象(默认)
- 使用
@Value注入简单类型,使用@Autowired注入引用类型
1.3.2 Bean 装入外部 properties 文件
- 在配置类中,添加注解
@PropertySource("jdbc.properties") - 在需要使用的地方,添加注解
@Value("${name}")
1.4 第三方 Bean 管理
1.4.1 简单类型依赖注入
public class JdbcConfig {
// 1. 定义一个方法获得要管理的 bean
// 2. 添加 @Bean 表示当前返回值是 Bean
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("application")
private String userName;
@Value("Uts_123456")
private String password;
@Bean
}
1.4.2 引用类型依赖注入
// 因为在BookDao 里面加了 @resposies 注解,自动装配
public DataSource dataSource(BookDao bookDao){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
1.5 总结
- XML 配置对比注解配置
1.6 Spring 整合 MyBatis
将配置文件 -> 转化为 配置类
- 导入相应依赖包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
JDBC 配置文件
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.setPassword(password);
ds.setUsername(userName);
ds.setUrl(url);
return ds;
}
}
Spring配置文件
@Configuration
@ComponentScan("com.lyq")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class, MybatisConfig.class})
public class SpringConfig {
}
MyBatis配置文件
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.lyq");
ssfb.setDataSource(dataSource);
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.lyq.dao");
return msc;
}
}
1.7 Spring 整合 Junit
- 导入依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
- 写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountServiceDao accountServiceDao;
@Test
public void testFindById(){
Account byId = accountServiceDao.findById(1);
System.out.println(byId);
}
@Test
public void testFindAll(){
System.out.println(accountServiceDao.findAll());
}
}
二、Spring AOP
作用:在不动原始设计基础上为其进行功能增强 Spring理念:无入侵式
2.1 核心概念
- 连接点 ( JoinPoint ):程序执行过程中的任意位置,粒度为执行方法、抛出异常﹑设置变量等在SpringAOP中,理解为方法的执行
- 切入点( Pointcut ) ∶匹配连接点的式子
- 在SpringAoP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
- 一个具体方法: com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
- 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
- 在SpringAoP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
- 通知( Advice ):在切入点处执行的操作,也就是共性功能
- 在SpringAoP中,功能最终以方法的形式呈现
- 通知类︰定义通知的类
- 切面(Aspect )︰描述通知与切入点的对应关系
2.2 AOP 入门案例思路分析
- 案例设定︰测定接口执行效率
- 简化设定︰在接口执行前输出当前系统时间开发模式︰XML or注解
- 思路分析:
- 导入坐标( pom.xml )
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>- 制作连接点方法(原始操作,Dao接口与实现类)
public interface AccountDao { public void save(); public void update(); }@Repository public class AccountDaoImpl implements AccountDao { public void save() { System.out.println("book dao save..."); } public void update() { System.out.println("book dao update..."); } }- 制作共性功能(通知类与通知)
- 定义切入点
@Aspect public class MyAdvice { @Pointcut("execution(void com.lyq.Dao.AccountDao.update())") private void pMethod(){} @Before("pMethod()") public void method(){ System.out.println(System.currentTimeMillis()); } }- 绑定切入点与通知关系(切面)
@Configuration @ComponentScan("com.lyq") @EnableAspectJAutoProxy public class SpringConfig { }
2.2 AOP 通知
2.2.1 AOP 通知类型
-
Before前置通知 -
After后置通知 -
Around环绕通知(重点)-
- 环绕通知
必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
- 环绕通知
-
- 通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
-
- 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值﹐必须设定为Object类型
-
- 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
-
- 由于无法预知原始方法运行后是否会抛出异常,因此
环绕通知方法必须抛出Throwable对象
- 由于无法预知原始方法运行后是否会抛出异常,因此
-
-
AfterReturing返回后通知(了解) -
抛出异常后通知(了解)
public class MyAdvice {
@Pointcut("execution(void com.lyq.Dao.AccountDao.update())")
private void fn(){}
@Pointcut("execution(int com.lyq.Dao.AccountDao.select())")
private void fn2(){}
//@Before("fn()")
public void before(){
System.out.println("before");
}
//@After("fn()")
public void after(){
System.out.println("after");
}
//@Around("fn()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before");
pjp.proceed();
System.out.println("around after");
}
@Around("fn2()")
public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before");
Object proceed = pjp.proceed();
System.out.println("around after");
return proceed;
}
//@AfterThrowing("fn()")
public void afterThrowing(){
System.out.println("afterThrowing");
}
}
案例:获取万次接口的执行时间
@Around("ProjectAdvice.servicePt()")
public void RunSpeed(ProceedingJoinPoint pjp) throws Throwable {
// 获取执行签名信息
Signature signature = pjp.getSignature();
// 通过签名获取执行类型(接口名)
String className = signature.getDeclaringTypeName();
// 通过签名获取执行操作名(方法名)
String methodName = signature.getName();
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
pjp.proceed();
}
long end = System.currentTimeMillis();
System.out.println(start - end);
}