1. 声明Bean的注解 72
负责声明Bean的注解,常见的包括四个:
● @Component
● @Controller
● @Service
● @Repository
1.1 源码如下:
1.1.1 @Component注解
package com.powernode.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Component {
String value();
}
1.1.2 @Controller注解
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
1.1.3 @Service注解
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
1.1.4 @Repository注解
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
1.2 通过源码可以看到
@Controller、@Service、@Repository这三个注解都是@Component注解的别名。
也就是说:这四个注解的功能都一样。用哪个都可以。
只是为了增强程序的可读性,建议:
● 控制器类上使用:Controller
● service类上使用:Service
● dao类上使用:Repository
他们都是只有一个value属性。value属性用来指定bean的id,也就是bean的名字。
2. Spring注解的使用 73
如何使用以上的注解呢?
● 第一步:加入aop的依赖
● 第二步:在配置文件中添加context命名空间
● 第三步:在配置文件中指定扫描的包
● 第四步:在Bean类上使用注解
第一步:加入aop的依赖
我们可以看到当加入spring-context依赖之后,会关联加入aop的依赖。所以这一步不用做。
第二步:在配置文件中添加context命名空间
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
第三步:在配置文件中指定要扫描的包
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--给Spring框架指定要扫描哪些包中的类-->
<context:component-scan base-package="com.powernode.spring6.bean"/>
</beans>
第四步:在Bean类上使用注解
package com.powernode.spring6.bean;
import org.springframework.stereotype.Component;
//Spring注解的使用 73
@Component("userBean")
public class User {
}
package com.powernode.spring6.bean;
import org.springframework.stereotype.Controller;
/**
* Spring注解的使用 73
**/
@Controller("vipBean") // 如果属性名是value的话,这个属性名可以省略。
public class Vip {
}
package com.powernode.spring6.bean;
import org.springframework.stereotype.Service;
/**
* Spring注解的使用 73
**/
@Service("orderBean") // 如果你把整个value属性全部省略了,bean有没有默认的名称?有:类名首字母变小写就是bean的名字。
public class Order {
}
package com.powernode.spring6.bean;
import org.springframework.stereotype.Repository;
/**
* Spring注解的使用 73
**/
@Repository("studentBean")
public class Student {
}
测试
//Spring注解的使用 73
@Test
public void testBeanComponent(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
Vip vipBean = applicationContext.getBean("vipBean", Vip.class);
System.out.println(vipBean);
//Order类和Student类我们不给value值,使用默认的
// 如果你把整个value属性全部省略了,bean有没有默认的名称?有:类名首字母变小写就是bean的名字。
//Order orderBean = applicationContext.getBean("orderBean", Order.class);
Order orderBean = applicationContext.getBean("order", Order.class);
System.out.println(orderBean);
//Student studentBean = applicationContext.getBean("studentBean", Student.class);
Student studentBean = applicationContext.getBean("student", Student.class);
System.out.println(studentBean);
// OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
// System.out.println(orderService);
//
// OrderDao orderDao = applicationContext.getBean("orderDao", OrderDao.class);
// System.out.println(orderDao);
}
3. 解决多包扫描问题 74
3.1 如果是多个包怎么办?有两种解决方案: 74
3.1.1 第一种:在配置文件中指定多个包,用逗号隔开。
com.powernode.spring6包下有两个包一个bean一个dao
package com.powernode.spring6.dao;
import org.springframework.stereotype.Component;
/**
* Spring注解的使用 73
**/
@Component
public class OrderDao {
}
<!--多个包,使用逗号隔开。-->
<context:component-scan base-package="com.powernode.spring6.bean,com.powernode.spring6.dao"/>
OrderDao orderDao = applicationContext.getBean("orderDao", OrderDao.class);
System.out.println(orderDao);
3.1.2 第二种:指定多个包的共同父包。 74
com.powernode.spring6包下有两个包一个bean一个dao
package com.powernode.spring6.dao;
import org.springframework.stereotype.Component;
/**
* Spring注解的使用 73
**/
@Component
public class OrderDao {
}
<!--多个包,也可以指定这多个包共同的父包,但是这肯定要牺牲一部分效率。-->
<context:component-scan base-package="com.powernode.spring6"/>
//解决多包问题 74
OrderDao orderDao = applicationContext.getBean("orderDao", OrderDao.class);
System.out.println(orderDao);
4. 选择性实例化Bean 75
假设在某个包下有很多Bean,有的Bean上标注了Component,有的标注了Controller,有的标注了Service,有的标注了Repository,现在由于某种特殊业务的需要,只允许其中所有的Controller参与Bean管理,其他的都不实例化。这应该怎么办呢?
use-default-filters="true" 表示:使用spring默认的规则,只要有Component、Controller、Service、Repository中的任意一个注解标注,则进行实例化。
use-default-filters="false" 表示:不再spring默认实例化规则,即使有Component、Controller、Service、Repository这些注解标注,也不再实例化。
表示只有Controller进行实例化。
<!--
第一种解决方案: 75
use-default-filters="false"
如果这个属性是false,表示com.powernode.spring6.bean2包下所有的带
有声明Bean的注解全部失效。@Component @Controller @Service @Repository全部失效。
-->
<context:component-scan base-package="com.powernode.spring6.bean2" use-default-filters="false">
<!--只有@Repository @Service 被包含进来,生效。-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
也可以将use-default-filters设置为true(不写就是true),并且采用exclude-filter方式排出哪些注解标注的Bean不参与实例化:
<!--
第二种解决方案: 75
use-default-filters="true"
如果这个属性的值是true,表示com.powernode.spring6.bean2下的所有的带有声明Bean的注解全部生效。
use-default-filters="true" 默认值就是true,不用写。
-->
<context:component-scan base-package="com.powernode.spring6.bean2">
<!--@Controller注解失效-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
package com.powernode.spring6.bean2;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
/**
* 选择性实例化Bean 75
**/
@Component
public class A {
public A() {
System.out.println("A的无参数构造方法执行");
}
}
@Controller
class B {
public B() {
System.out.println("B的无参数构造方法执行");
}
}
@Service
class C {
public C() {
System.out.println("C的无参数构造方法执行");
}
}
@Repository
class D {
public D() {
System.out.println("D的无参数构造方法执行");
}
}
@Controller
class E {
public E() {
System.out.println("E的无参数构造方法执行");
}
}
//选择性实例化Bean 75
@Test
public void testChoose(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-choose.xml");
}