文章目录
Spring注解开发
Spring的开发大体可分为两类:XML配置和注解开发。
本文主要讲解纯注解开发的形式。实际应用中可根据情况结合进行。
一、配置文件
配置文件分为两种方式:XML配置文件、Config配置类
1、xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--自动扫描指定的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.zyh.pojo"/>
</beans>
2、Config配置类
自己创建一个Config类,在创建的类上面加上@Configuration
注解,该类就变为Spring的配置类。
@Configuration
@ComponentScan({"com.zyh.pojo","com.zyh.service"})//扫描包下的bean对象
//@Import(MyConfig2.class) 导入其他配置类
public class SpringConfig {
@Bean
public People people(){
return new People();
}
}
这些代码就创建了一个基础的配置文件。实际上是取代了xml当中的以下代码:
其中上图配置类中的@ComponentScan("com.zyh.pojo")
等同于xml方法中中配置文件中的<context:component-scan base-package="com.zyh.pojo"/>
。
@Configuration
等同于其余代码。
如上代码所示,一个简单的配置类就创建好了,也就相当于创建好了一个容器,那么怎么将外面的bean对象注入到容器中呢?下面介绍两种方式。
二、创建并注入bean对象
将bean对象注入Config配置类的方法有两种:
1.在配置类中创建方法,上面@Bean。
@Configuration
@ComponentScan({"com.zyh.pojo","com.zyh.service"})
//@Import(MyConfig2.class) 导入其他配置类
public class SpringConfig {
@Bean
public People people(){
return new People();
}
}
2.在实体类上加@Component
在实体类上加@Component
,config配置文件扫描到该注解会自动创建bean对象。
@Component("user") // 不加括号名,则名字默认未类名(首字母小写)
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
@Value("猪猪")
// 相当于配置文件中 <property name="name" value="猪猪"/>
public String name;
//要给出getter方法,但可以不用给出setter方法了
public String getName() {
return name;
}
}
Spring提供了@Component注解的三个衍生注解:
@Controller:用于表现层bean定义
@Service:用于业务层bean定义
@Repository:用于数据层(dao层)bean定义
这四中注解是等价的关系,都能被@ComponentScan
扫描到。
问:那为什么有了@Compent,还需要@Bean呢?
如果你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component注解的,因此就不能使用自动化装配的方案了,但是我们可以使用@Bean,当然也可以使用XML配置。
3. 更改初始化容器代码
从这可以和xml对比这看,配置类初始化时改成了new AnnotationConfigApplicationContext(SpringConfig.class);
但此处只写了初始化容器代码,至于简单测试的话下面还需要写ctx.getBean()
来拿到具体的对象进行操作。
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
// 加載xml配置文件初始化容器
//ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 加載配置類初始化容器
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = ctx.getBean("user",User.class);
System.out.println(user.getName());
}
}
以上说的是从配置方法上分的两大类。下面说的是纯注解方式的一些要点。
三、依赖注入(自动装配)
创建完bean对象后,那类中的简单属性怎么赋值,复杂类属性怎么转配呢?
解答:
类中的简单属性用@Value("名称")
进行赋值。
类中的复杂类属性,用下面两种注解进行装配:
@Autowired:自动按类型装配
@Qualifier("people") :注入指定的bean对象,当有多个相同的类型时,就要用这种方式。
案例:User类中添加了People类作为属性。
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
@Autowired // 自动按类型装配
@Qualifier("people") // 注入指定的bean对象
private People people;
@Value("猪猪")
// 相当于配置文件中 <property name="name" value="猪猪"/>
private String name;
//要给出getter方法,但可以不用给出setter方法了
public String getName() {
return name;
}
public void save(){
people.say();
}
}
测试类中,可以用user.save()方法,调用的people中的say()方法,就可以知道People类装配成功。
四、加载properties配置文件
加载配置文件,最熟悉最基础的就是jdbc.properties配置文件,无非就是两个问题:
1.config配置注解的形式怎么加载到这个文件?
2.加载好之后怎么用?
properties文件以jdbc为例,切只写了name作为示范:
@PropertySource("jdbc.properties")
让config配置文件加载到properties
@Configuration
@ComponentScan({"com.zyh.pojo","com.zyh.service"})
@PropertySource("jdbc.properties")
//@Import(MyConfig2.class) 导入其他配置类
public class SpringConfig {
}
- 在需要赋的属性上用
@Value("${name}")
,这样该属性就和properties中的name的key对应上。测试中调用getName会打印出root。
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
@Value("${name}")
private String name;
//要给出getter方法,但可以不用给出setter方法了
public String getName() {
return name;
}
}
注意事项:
- 加载多个properties文件格式:
@PropertySource({"jdbc.properties","jdbc2.properties"})
- 不支持使用通配符,例如:
@PropertySource("*.properties")
会报错。
五、Spring整合MyBatis
mybatis的作用是简化jdbc的开发,简单的讲就是mybatis框架要整合jdbc进来,spirng框架要把mybatis整合进来,一层套一层。
1.原生jdbc配置
原生jdbc的properties文件如下所示:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/zyhtest?userSSL=false&&serverTimezone=GMT&&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=1234
2.mybatis加入jdbc
将jdbc文件加入到mybatis.xml文件中,并把以上代码存在在DataSource区域内,作为一个资源对象。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"></properties> <!--读入jdbc文件-->
<typeAliases>
<package name="com.zyh.pojo"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.zyh.dao"></package> <!--扫描mapper层的接口-->
</mappers>
</configuration>
3.增加配置类
到现在为止,mybatis的所有配置都在外部文件中写完了,但还没有整合进spring框架当中。要想整合进去,需要将这些配置导入配置类中。为了清晰分类,最好创建一个专属于jdbc的配置类和专属于mybatis的配置类。
(1)jdbc配置类
将jdbc中的内容加载到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;
}
}
(2)mybatis配置类
mybatis中最主要的就是创建sqlsessionfactory,在spring中提供了一个专门的类:SqlSessionFactoryBean,要报datasource对象装配进去。
public class MybatisConfig {
//对应mybatis.xml文件中其他内容
// 如果通过@Bean方式创建的对象,要想在其中再注入对象的话,在方法中加参数即可,参数会按类型自动到容器中匹配注入。
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.zyh.pojo");
ssfb.setDataSource(dataSource);
return ssfb;
}
// 对应mybatis.xml配置文件中的<mapper>标签中的内容
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer mscf = new MapperScannerConfigurer();
mscf.setBasePackage("com.zyh.dao");
return mscf;
}
}
创建完SqlSessionFactoryBean
对象,等同于mybatis.xml配置中<mapper>
以外的部分,下面单独创建mapper对象即等同于原来这个xml文件。
(3)导入主配置类
利用@Import({JdbcConfig.class,MybatisConfig.class})
导入上述两个配置类。
@Configuration
@ComponentScan("com.zyh")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class}) // 导入其他配置类
public class SpringConfig {
}
整体思维图如下:
六、注解实现AOP
我们总线上的编程是纵向编程思想,需要用到的主要实际类方法就那些,但在公司中基于业务的考虑,会要求加入在功能的前后加入通知、日志、异常抛出通知等一系列的附加功能,这些功能就需要在service层横切进去,在代理中加入。
而这些操作,在spring的aop中已经帮你做好了接口,你只需要实现它即可。例如要在方法之前插入就实现 MethodBeforeAdvice接口。
AOP所遇到的问题有一下几点:
- 在什么位置切入?
- 怎么切入?
- 怎么实现附加功能?
1.在什么位置切入
先定义切入点,切入点包含具体切入到哪个包下的哪个类。注解的方式如下:
@Pointcut("execution(int com.zyh.service.UserService.select())")
ececution(方法类型 扫描包.方法名(参数个数))
//相当于保留针头,现将切入点创建出来,后面任何方法只要怼入即可
// @Pointcut("execution(void com.zyh.service.UserService.add())")
// @Pointcut("execution(* com.zyh.service.UserService.add(*))") //方法里必须有参数(失败)
// @Pointcut("execution(* com.*.*.*.add())") // (成功)一个 *. 对应一层包,可以使这一层的任意一个包,但只能匹配这一层
// @Pointcut("execution(* *..*(..))") // (成功)代表任意返回值,任意包下的任意方法的任意参数。即所有方法全部匹配。
// *.. 代表包下的任意内容,可以跨越好几层
@Pointcut("execution(* com.zyh.*.*Service.*e(..))") // (成功)代表:zyh包下的任意包下的以Service结尾的接口(或类)下的以e结尾的方法。
private void pt(){}
@Pointcut("execution(int com.zyh.service.UserService.select())")
private void pt2(){}
2.怎么切入
AOP有五种通知类型:
@Befor:前置通知
@After:后置通知
@Around:环绕通知
@AfterReturning:返回后通知
@AfterThrowing:抛出异常后通知
已知上面定义好了切入点,将切入点传入这五种注解中,就将切点和连接点对应起来。如下所示代表在select方法执行前,先执行输出before语句。
@Before("pt()")
public void before(){
System.out.println("before");
}
3.怎么实现附加功能
至于怎么实现附加功能,在上述注解下面的方法中写即可。
注:
至此spring注解开发的基础内容基本就是这些,但这只是最基础部分,只是为了更好地梳理逻辑,更好地理解其作用。剩下的仍需要慢慢研究。