一、Bean管理包括两个操作: 1、Spring创建对象 2、Spring注入属性 二、什么是注解? 1、注解是代码中的特殊标记,格式为:@注解名称(属性名称 = 属性值, 属性名称 = 属性值…) 2、注解可以使用在类、属性、方法 3、使用注解的目的:简化XML配置文件的使用 4、Spring针对Bean管理中对象创建提供的注解有: (1)@Component 用来标注一个类为Spring容器的Bean。 (2)@Service 一般使用在业务逻辑层、service层。 (3)@Controller 一般使用在web层。 (4)@Repository 一般使用在持久层、Dao层。 *上面四个注解都可以用来创建bean实例 三、实现 操作步骤: 1、引入依赖 除了Spring最基本的依赖以外,还需要aop的依赖 全部的依赖如下:
2、开启组件扫描 所谓组件扫描就是告诉Spring我们需要在哪些类上面添加注解 3、实现 项目结构: UserService类:
package com.java.spring5.Service;
import org.springframework.stereotype.Component;
@Component(value = "userService")
public class UserService {
String name;
public void add () {
System.out.print("userService add...");
}
}
其实在这里也可以使用@Controller、@Service、@Repository做到一样的效果。 配置文件:
<?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:p="http://www.springframework.org/schema/p"
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" >
<!--开启组件扫描
第一步:引入context名称空间,如上
第二步:开启组件扫面,使用context:component-scan标签的base-package属性进行指定我们需要扫描的类的路径
如果需要扫描多个包,使用,隔开,或者扫描多个包的上层目录-->
<context:component-scan base-package="com.java.spring5"></context:component-scan>
</beans>
测试方法:
@Test
public void test1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.add();
}
分析:首先加载配置文件,按照配置文件中的配置区扫描com.java.spring5包,扫描到一个加上注解的UserService类,然后进行创建实例 四、扫描filter配置 如上所示的我们会去扫描com.java.spring5下的所有的类,其实我们是可以单独配置可以扫描哪些,哪些又不可以扫描的。主要是使用context:include-filter、context:exclude-filter两个标签来进行控制,入邪配置文件所述。
<?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:p="http://www.springframework.org/schema/p"
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" >
<!--开启组件扫描
第一步:引入context名称空间,如上
第二步:开启组件扫面,使用context:component-scan标签的base-package属性进行指定我们需要扫描的类的路径
如果需要扫描多个包,使用,隔开,或者扫描多个包的上层目录-->
<context:component-scan base-package="com.java.spring5"></context:component-scan>
<!--实例一:
use-default-filters="false" 表示现在不使用默认的filter,而是使用自己配置的filter
context:include-filter 既是配置我们扫描哪些内容。
type="annotation"则是配置我们扫描注解,
expression="org.springframework.stereotype.Service"则是扫描配置了注解@service的类-->
<context:component-scan base-package="com.java.spring5" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<!--实例二:
与实例一不同,在这里我们扫描com.java.spring5包下的所有类,而使用context:exclude-filter配置不扫描哪些内容的,相同的
type="annotation"则是配置我们扫描注解,
expression="org.springframework.stereotype.Controller"则是不扫描配置了注解@Controller的类-->
<context:component-scan base-package="com.java.spring5">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
五、基于注解方式实现属性注入 在这里会涉及到几个注解: @Autowired:根据属性类型进行自动注入 @Qualifier:根据属性名称进行注入 @Resource :可以根据属性类型、也可以根据属性的名称进行注入 @Value:注入普通类型属性 1、@Autowired注解 第一步:在service和dao中创建出相对应的类,并给类加上创建对象的注解。第二步:在service中注入dao对象,在service类中添加dao类型属性,在属性上面添加注入注解 Dao层的接口以及实现类如下:
package com.java.spring5.Dao;
public interface UserDao {
void add();
}
package com.java.spring5.Dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoIpml implements UserDao{
public void add() {
System.out.print("userDao add...");
}
}
Service层
package com.java.spring5.Service;
import com.java.spring5.Dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService2 {
@Autowired
UserDao userDao;
public void userServiceAdd() {
userDao.add();
}
}
测试类:
@Test
public void autoWiredTest() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
UserService2 userService2 = applicationContext.getBean("userService2", UserService2.class);
userService2.userServiceAdd();
}
运行结果: 注:我们使用注解方法去注入属性的时候,不需要要求注入属性所在的类有set方法,因为已经封装好了。 2、@Qualifier 情景: 如上Dao层中的UserDao接口有一个实现类的话我们可以使用@Autowired按照类型进行注入,但是如果UserDao有多个实现类,如下所示: 那么运行刚刚的测试方法会抛出异常:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.java.spring5.Dao.UserDao' available: expected single matching bean but found 2: userDaoIpml,userDaoIpml2
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1285)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657)
揪出其中重要的部分:
No qualifying bean of type 'com.java.spring5.Dao.UserDao' available: expected single matching bean but found 2: userDaoIpml,userDaoIpml2
也就是说有两个实现类,我不知道该选择哪一个进行注入。为了解决这一问题,我们就可使用@Qualifier注解进行注入属性,根据属性名称进行注入。如下: 第一步:给第二个实现类的代码如下:
package com.java.spring5.Dao;
import org.springframework.stereotype.Component;
@Component
public class UserDaoIpml2 implements UserDao {
@Override
public void add() {
System.out.print("UserDaoIpml2 add.....");
}
}
第二步:给UserDao增加@Qualifier注解
package com.java.spring5.Service;
import com.java.spring5.Dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class UserService2 {
@Autowired
@Qualifier(value = "userDaoIpml2")
UserDao userDao;
public void userServiceAdd() {
userDao.add();
}
}
同样运行上面的测试方法,运行结果: 可能小伙伴们很疑惑为什么只使用@Qualifier进行注入,我将@Autowired注解去掉,运行会报空指针异常,目前我还不知道为什么。这里可能就需要去读读源码了。 总结:@Qualifier注解需要和@Autowired注解一起使用,如果单独使用会报空指针异常。 3、@Resource 使用@Resource注入属性与@Autowired注入属性有一个相同的问题:如果一个接口有多个实现类,那如果我们不给@Resource指定实现类的名字也会报异常,异常信息与@Autowired出现异常信息一样。如下是@Resource注解的使用:
package com.java.spring5.Service;
import com.java.spring5.Dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService2 {
@Resource(name = "userDaoIpml2")
UserDao userDao;
public void userServiceAdd() {
userDao.add();
}
}
总结:虽然@Resource注解可以做到根据属性值与属性类型进行注入的功能,但是@Resource不是Spring的,是java的扩展包中,所以Spring并不建议我们使用@Resouce,通常我们使用@Autowired根据属性类型如注入属性。 4、@value @Value主要是用来注入String、int等等普通类型的属性 使用如下:
package com.java.spring5.Service;
import com.java.spring5.Dao.UserDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService2 {
@Resource(name = "userDaoIpml2")
UserDao userDao;
@Value(value = "abc")
String userName;
public void userServiceAdd() {
userDao.add();
System.out.print(this.userName);
}
}
运行结果: 六、完全注解 在上面的例子当中,我们虽然比完全使用配置文件时配置文件的类容变少了,但还是会有那么一点繁琐。所谓完全注解,就是在不依赖配置文件去扫描注解。 第一步:创建配置类替换掉xml配置文件 1、使用@Configuration让Spring知道当前类时配置类 2、使用@ComponentScan注解开启扫描注解 basePackages属性:开启扫描包。示例:@ComponentScan(basePackages = {“com.java.spring5”}) 相当于我们之前配置文件中的 <context:component-scan base-package=“com.java.spring5”></context:component-scan> basePackageClasses:开启扫描某个类所在包下的所有注解。 第二步:对象的创建与属性的注入方式不变,不同的是测试方法,测试方法如下:
@Test
public void noConfigTest() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService2 userService2 = context.getBean("userService2", UserService2.class);
userService2.userServiceAdd();
}
运行结果:
|