概述
四、Spring注解式开发
1. 概述
Spring是开发中必不可少的一个框架,基于传统的xml方式配置太过繁琐,从spring2.5之后注解的出现可以大大简化配置。
1.1 Xml优缺点
优点:
- 把类与类之间松解偶,修改方便,容易扩展
- 容易和其他系统进行数据交互
- 对象之间的关系一目了然
缺点:
- 配置冗长,需要额外维护,影响开发效率
- 类型不安全,校验不出来,出错不好排查
1.2 注解优缺点
优点:
- 简化配置
- 使用起来直观且容易,提升开发的效率
- 类型安全,容易检测出问题
缺点:
- 修改起来比xml麻烦
- 如果不项目不了解,可能给开发和维护带来麻烦
**注解简单概括:**写起来比较简单、方便,看起来也简洁,但是修改麻烦
**Xml配置概括:**写起来比较灵活、修改方便,但是写和维护麻烦
2. 开启注解
2.1 组件扫描
- 组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件,使Spring中的注解生效
- 对于扫描到的组件,Spring有默认的命名规则:使用首字母小写的类名,作为默认bean的名称,也可以在注解中通过value属性值标识组件的名称
- 在Spring的配置文件中声明
<context:component-scan>
标签,实现组件扫描 <context:component-scan>
标签的base-package属性指定一个需要扫描的基础类包,Spring容器将会扫描这个基础类包里及其子包中的所有类- 当需要扫描多个包时,可以使用逗号分隔;或配置多个
<context:component-scan>
标签
<!-- 组件扫描-->
<context:component-scan base-package="com.newcapec.bean"/>
<context:component-scan base-package="com.newcapec.dao"/>
<context:component-scan base-package="com.newcapec.service"/>
<context:component-scan base-package="com.newcapec.controller"/>
2.2 扫描过滤
如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类
<!-- 粗粒度过滤 -->
<context:component-scan base-package="com.newcapec" resource-pattern="bean/*.class"/>
细粒度的过滤,可采用子标签<context:include-filter>
表示要包含的目标类和<context:exclude-filter>
表示要排除在外的目标类。其中type属性有以下5种:
- annotation:过滤器扫描使用注解所标注的那些类,通过expression属性指定要扫描的注释
- assignable:过滤器扫描派生于expression属性所指定类型的那些类
- aspectj:过滤器扫描与expression属性所指定的AspectJ表达式所匹配的那些类
- regex:过滤器扫描类的名称与expression属性所指定正则表示式所匹配的那些类
- custom:使用自定义的org.springframework.core.type.TypeFliter实现类,该类由expression属性指定
**注意:**若使用<context:include-filter>
去过滤扫描内容,要在use-default-filters="false"的情况下,不然会失效,被默认的过滤机制所覆盖。在use-default-filters="false"的情况下,exclude-filter是针对include-filter里的内容进行排除
不包含:
@Component
public class Dog {
@Override
public String toString() {
return "Dog";
}
}
@Component
public class SmallDog extends Dog {
@Override
public String toString() {
return "SmallDog";
}
}
<!-- 细粒度过滤 -->
<!-- 默认扫描规则:base-package下所有的类,所有的子包,所有子包下的类都会被扫描 -->
<context:component-scan base-package="com.newcapec">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="assignable" expression="com.newcapec.bean.Dog"/>
</context:component-scan>
仅包含:
<context:component-scan base-package="com.newcapec" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
3. 配置Bean
- @Component:基本注解,标识一个受Spring管理的组件
- @Respository:标识持久层组件
- @Service:标识服务层(业务层)组件
- @Controller:标识表现层组件
公有属性value:表示Bean的名称
@Component
public class Person {
private int id;
private String name;
private double money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + ''' +
", money=" + money +
'}';
}
}
public interface DemoDao {
void insertDemo();
}
@Repository("demoDao")
public class DemoDaoImpl implements DemoDao {
@Override
public void insertDemo() {
System.out.println("dao中实现数据新增........");
}
}
public interface DemoService {
void insertDemo();
}
@Service("demoService")
public class DemoServiceImpl implements DemoService {
@Override
public void insertDemo() {
System.out.println("service中实现数据新增........");
}
}
@Controller
public class DemoController {
public void insertDemo(){
System.out.println("controller中实现数据新增.......");
}
}
测试
public class AnnotationTest {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Person p1 = ac.getBean("person", Person.class);
System.out.println(p1);
DemoDao demoDao = ac.getBean("demoDao", DemoDao.class);
demoDao.insertDemo();
DemoService demoService = ac.getBean("demoService", DemoService.class);
demoService.insertDemo();
DemoController demoController = ac.getBean("demoController", DemoController.class);
demoController.insertDemo();
SmallDog smallDog = ac.getBean("smallDog" ,SmallDog.class);
System.out.println(smallDog);
Dog dog = ac.getBean("dog", Dog.class);
System.out.println(dog);
}
}
4. 组件装配
@Value:为组件属性注入字面值
@Autowired和@Resource:自动装配注解,即自动注入
@Autowired:默认按照类型装配
- 构造方法,普通属性(即使是非public),一切具有参数的方法都可以使用@Authwired注解
- 所有使用@Autowired注解的属性都要求依赖的bean对象必须存在。当Spring找不到匹配的bean装配属性时,会抛出异常。若该属性允许为null值,可以设置@Authwired注解的required属性为false
- 当IOC容器里存在多个类型兼容的bean对象时,通过类型的自动装配将无法工作。此时可以在@Qualifier注解里提供bean的名称,Spring会通过名称自动装配
- @Authwired注解也可以应用在数组类型的属性上,此时Spring将会把所有匹配的bean进行自动装配
- @Authwired注解也可以应用在集合属性上,此时Spring读取该集合的类型信息,然后自动装配所有与之兼容的bean
- @Authwired注解用在java.util.Map上时,若该Map的键值为String,那么Spring将自动装配与之Map值类型兼容的bean,此时bean的名称作为键值
@Service("demoService")
public class DemoServiceImpl implements DemoService {
@Autowired(required = false)
@Qualifier("demoDao")
private DemoDao demoDao;
@Override
public void insertDemo() {
System.out.println("service中实现数据新增........");
demoDao.insertDemo();
}
}
@Resource:默认按照名称装配
- @Resource注解要求提供一个bean名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为bean的名称
- @Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动装配策略,而使用type属性时则使用byType自动装配策略。如果既不指定name也不指定type属性,这时将先使用byName自动装配策略,装配不成功,再才用byType装配
@Controller
public class DemoController {
@Resource
private DemoService demoService;
public void insertDemo(){
System.out.println("controller中实现数据新增.......");
demoService.insertDemo();
}
}
5. Java Config
JavaConfig,是在 Spring 3.0 开始从一个独立的项目并入到 Spring 中的。JavaConfig 可以看成一个用于完成 Bean 装配的 Spring 配置文件,即 Spring 容器,只不过该容器不是 XML文件,而是由程序员使用 Java 自己编写的 Java 类。
Dept.java
public class Dept {
private int deptno;
private String dname;
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + ''' +
'}';
}
}
Emp.java
public class Emp {
private int empno;
private String ename;
private Dept dept;
public int getEmpno() {
return empno;
}
public void setEmpno(int empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + ''' +
", dept=" + dept +
'}';
}
}
配置类:
定义 JavaConfig 类,在类上使用@Configuration 注解,将会使当前类作为一个 Spring 的容器来使用,用于完成 Bean 的创建。在该 JavaConfig 的方法上使用@Bean,将会使一个普通方法所返回的结果变为指定名称的 Bean 实例。
//该注解表示这个类为javaConfig类
@Configuration
public class MyConfig {
//该注解表示:将一个叫做dept的对象放入IOC容器中
@Bean("dept")
public Dept getDept() {
Dept dept = new Dept();
dept.setDeptno(10);
dept.setDname("研发部");
return dept;
}
//该注解表示:将一个叫做emp的对象放入IOC容器中
//并且通过byType的方式注入dept
@Bean(name="emp",autowire=Autowire.BY_TYPE)
public Emp getEmp() {
Emp emp = new Emp();
emp.setEmpno(8001);
emp.setEname("张三");
return emp;
}
}
测试
public class JavaConfigTest {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Dept dept = ac.getBean("dept", Dept.class);
System.out.println(dept);
Emp emp = ac.getBean("emp", Emp.class);
System.out.println(emp);
}
}
6. AOP的实现
6.1 开启AOP注解
<!-- 开启AOP注解 -->
<aop:aspectj-autoproxy/>
6.2 AOP中使用的注解
- @Aspect:配置切面类
- @Before:配置前置通知
- @After:配置后置通知
- @AfterReturning:配置返回通知
- @AfterThrowing:配置异常通知
- @Order:配置切面优先级
- @Pointcut:配置切点表达式
@Component
@Aspect
@Order(2)
public class LogAspect {
@Before("execution(* com.newcapec.dao.DemoDaoImpl.*(..))")
public void beforeMethod(){
System.out.println("AOP日志记录:前置通知......");
}
//公共切点表达式
@Pointcut("execution(* com.newcapec.dao.DemoDaoImpl.*(..))")
public void exp(){}
@After("exp()")
public void afterMethod(){
System.out.println("AOP日志记录:后置通知......");
}
@AfterReturning(value = "exp()",returning = "result")
public void afterReturnMethod(Object result){
System.out.println("AOP日志记录:返回通知......" + result);
}
@AfterThrowing(value = "exp()", throwing = "ex")
public void afterThrowMethod(Exception ex){
System.out.println("AOP日志记录:异常通知......" + ex);
}
}
@Component
@Aspect
@Order(1)
public class OtherAspect {
@Before("execution(* com.newcapec.dao.DemoDaoImpl.*(..))")
public void beforeM(){
System.out.println("OtherAspect的beforeM方法.....");
}
}
7. 事务管理
7.1 启用事务注解
<!-- 1.配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 2.开启事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
7.2 事务注解
在事务方法上加注解@Transactional
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED,
readOnly = true,timeout = 20,rollbackFor = {ClassNotFoundException.class})
public void transfer(int fromId, int toId, double money) throws Exception {
}
最后
以上就是可爱雪糕为你收集整理的Spring注解式开发四、Spring注解式开发的全部内容,希望文章能够帮你解决Spring注解式开发四、Spring注解式开发所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复