4. 基于XML管理Bean
4.13 FactoryBean
4.13.1 FactoryBean位置
4.13.2 实现
- 项目结构
- User
package com.example.bean;
public class User {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{"
"id=" id
", name='" name '''
'}';
}
}
- UserFactoryBean
package com.example.factory;
import com.example.bean.User;
import org.springframework.beans.factory.FactoryBean;
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
- bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.example.bean.User">
<property name="id" value="1001"></property>
<property name="name" value="admin"></property>
</bean>
<bean id="factory" class="com.example.factory.UserFactoryBean"></bean>
</beans>
- UserFactoryBeanTest
import com.example.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserFactoryBeanTest {
@Test
public void testUserFactoryBean(){
//获取IOC容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
User user = (User) ac.getBean("factory");
System.out.println(user);
}
}
4.14 基于xml自动装配
- 自动装配:根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值
- 使用bean标签的autowire属性设置自动装配效果
- 自动装配方式:byType
byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值 若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null 若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException
- 自动装配方式:byName
byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值???
- 实现
UserDao
代码语言:javascript复制package com.example.dao;
public interface UserDao {
void saveUser();
}
UserDaoImpl
代码语言:javascript复制package com.example.dao.impl;
import com.example.dao.UserDao;
public class UserDaoImpl implements UserDao {
public void saveUser(){
System.out.println("save user....");
}
}
UserService
代码语言:javascript复制package com.example.service;
public interface UserService {
void saveUser();
}
UserServiceImpl
代码语言:javascript复制package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.service.UserService;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void saveUser() {
userDao.saveUser();
}
}
UserController
代码语言:javascript复制package com.example.controller;
import com.example.service.UserService;
public class UserController {
private UserService userService1;
public void setUserService(UserService userService) {
this.userService1 = userService;
}
public void saveUser(){
userService1.saveUser();
}
}
beanByType.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 自动装配 byType -->
<bean id="userController" class="com.example.controller.UserController" autowire="byType"></bean>
<bean id="userService" class="com.example.service.impl.UserServiceImpl" autowire="byType"></bean>
<bean id="userDao" class="com.example.dao.impl.UserDaoImpl"></bean>
</beans>
beanByName.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 自动装配 byName -->
<bean id="userController" class="com.example.controller.UserController" autowire="byName"></bean>
<bean id="userService" class="com.example.service.impl.UserServiceImpl" autowire="byName"></bean>
<!-- <bean id="userServiceImpl" class="com.example.service.impl.UserServiceImpl" autowire="byName"></bean>-->
<bean id="userDao" class="com.example.dao.impl.UserDaoImpl"></bean>
<!-- <bean id="userDaoImpl" class="com.example.dao.impl.UserDaoImpl"></bean>-->
</beans>
AutoTest
代码语言:javascript复制import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AutoTest {
@Test
public void testByType(){
ApplicationContext app = new ClassPathXmlApplicationContext("beanByType.xml");
UserController userController = app.getBean(UserController.class);
userController.saveUser();
}
@Test
public void testByName(){
ApplicationContext app = new ClassPathXmlApplicationContext("beanByName.xml");
UserController userController = app.getBean(UserController.class);
userController.saveUser();
}
}
4.15 工厂方法实例化
代码语言:javascript复制<!-- 工厂静态方法实例化-->
<bean id="userDaoStaticFactory" class="com.example.factory.UserStaticFactory" factory-method="getUserDao" scope="prototype"></bean>
<!-- 工厂动态方法实例化-->
<bean id="factory" class="com.example.factory.UserDynamicFactory" scope="prototype"></bean>
<bean id="userDaoDynamicFactory" factory-bean="factory" factory-method="getUserDao" scope="prototype"></bean>
- UserStaticFactory
package com.example.factory;
import com.example.dao.UserDao;
import com.example.dao.impl.UserDaoImpl;
public class UserStaticFactory {
public static UserDao getUserDao(){
System.out.println("StaticFactory:getUserDao...");
return new UserDaoImpl();
}
}
- UserDynamicFactory
package com.example.factory;
import com.example.dao.UserDao;
import com.example.dao.impl.UserDaoImpl;
public class UserDynamicFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
5. 基于注解管理Bean
5.1 组件扫描
5.1.1 基础
- 开启组件扫描
<context:component-scan base-package="com.example"></context:component-scan>
- type:扫描类型
- context:exclude-filter标签:排除
<context:component-scan base-package="com.example">
<!-- type="annotation",根据注解排除,expression中设置要排除的注解的全类名 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<!-- type="assignable",根据类型排除,expression中设置要排除的类型的全类名 -->
<!--<context:exclude-filter type="assignable" expression="com.example.bean.User"/>-->
</context:component-scan>
- context:include-filter标签:指定在原有扫描规则的基础上追加的规则
- use-default-filters属性:取值false表示关闭默认扫描规则。要指定包含的注解,必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类
<context:component-scan base-package="com.example" use-default-filters="false">
<!-- type="annotation",根据注解包含,expression中设置要包含的注解的全类名 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<!-- type="assignable",根据类型包含,expression中设置要包含的类型的全类名 -->
<!-- <context:include-filter type="assignable" expression="com.example.bean.User"/> -->
</context:component-scan>
5.1.2 实现
- 项目结构
- Person
package com.example.bean;
import org.springframework.stereotype.Repository;
@Repository
public class Person {
}
- User
package com.example.bean;
import org.springframework.stereotype.Component;
@Component
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- exclude-bean.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
http://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.example">
<!-- type:设置排除或包含的依据 -->
<!-- type="annotation",根据注解排除,expression中设置要排除的注解的全类名 -->
<!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/> -->
<!-- type="assignable",根据类型排除,expression中设置要排除的类型的全类名 -->
<!-- <context:exclude-filter type="assignable" expression="com.example.bean.User"/> -->
</context:component-scan>
</beans>
- include-bean.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
http://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.example" use-default-filters="false">
<!--
context:include-filter标签:指定在原有扫描规则的基础上追加的规则
use-default-filters属性:取值false表示关闭默认扫描规则
要指定包含的注解,必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类
-->
<!-- type="annotation",根据注解包含,expression中设置要包含的注解的全类名 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<!-- type="assignable",根据类型包含,expression中设置要包含的类型的全类名 -->
<!-- <context:include-filter type="assignable" expression="com.example.bean.User"/> -->
</context:component-scan>
</beans>
- ComponentScanTest
import com.example.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ComponentScanTest {
@Test
public void test(){
ApplicationContext app = new ClassPathXmlApplicationContext("exclude-bean.xml");
User user = app.getBean("user", User.class);
user.setName("张三");
System.out.println(user.getName());
ApplicationContext app2 = new ClassPathXmlApplicationContext("include-bean.xml");
User user2 = app2.getBean("user", User.class);
user2.setName("李四");
System.out.println(user2.getName());
}
}
5.1.3 使用注解定义 Bean
Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。
注解 | 说明 |
---|---|
@Component | 该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。 |
@Repository | 该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。 |
@Service | 该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。 |
@Controller | 该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。 |
5.2 Autowired
- 单独使用@Autowired注解,默认根据类型装配。【默认是byType】
package org.springframework.beans.factory.annotation;
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;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
源码中有两处需要注意:
- 第一处:该注解可以标注在:构造方法上、方法上、形参上、属性上、注解上
- 第二处:该注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错。
5.2.1 属性上
- UserDao
package com.example.dao;
public interface UserDao {
void addUser();
}
- UserDaoImpl
package com.example.dao.impl;
import com.example.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("add user....");
}
}
- UserService
package com.example.service;
public interface UserService {
void addUser();
}
- UserServiceImpl
package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void addUser() {
userDao.addUser();
}
}
- UserController
package com.example.controller;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
@Autowired
private UserService userService;
public void addUser(){
userService.addUser();
}
}
- property-bean.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 http://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.example"></context:component-scan>
</beans>
- AutowiredTest
import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AutowiredTest {
@Test
public void test(){
ApplicationContext app = new ClassPathXmlApplicationContext("property-bean.xml");
UserController userController = app.getBean(UserController.class);
userController.addUser();
}
}
- 构造方法和setter方法都没有提供,仍然可以注入成功
5.2.2 方法上
- UserServiceImpl
package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser() {
userDao.addUser();
}
}
- UserController
package com.example.controller;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void addUser(){
userService.addUser();
}
}
5.2.3 构造方法上
- UserServiceImpl
package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser() {
userDao.addUser();
}
}
- UserController
package com.example.controller;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
public void addUser(){
userService.addUser();
}
}
5.2.4 形参上
- UserServiceImpl
package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(@Autowired UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser() {
userDao.addUser();
}
}
- UserController
package com.example.controller;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
private UserService userService;
public UserController(@Autowired UserService userService) {
this.userService = userService;
}
public void addUser(){
userService.addUser();
}
}
5.2.5 只有一个有参构造函数,无@Autowired
- UserServiceImpl
package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser() {
userDao.addUser();
}
}
- UserController
package com.example.controller;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public void addUser(){
userService.addUser();
}
}
- 当有参数的构造方法只有一个时,@Autowired注解可以省略。有多个构造方法时,测试报错
5.2.6 @Autowired注解和@Qualifier注解联合
- 新增文件 UserRedisDaoImpl
package com.example.dao.impl;
import com.example.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository
public class UserRedisDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("UserRedisDaoImpl add user ...");
}
}
- 进行测试,报错=》有两个userDao,@Autowired注入的时候,根据类型注入,不知道用哪个
- 解决:UserServiceImpl用@Autowired的同时,用@Qualifier注解指定bean的名字
package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("userDaoImpl") // 指定bean的名字
private UserDao userDao;
@Override
public void addUser() {
userDao.addUser();
}
}
- 再次测试,通过
5.2.7 总结
- @Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上。
- 当带参数的构造方法只有一个,@Autowired注解可以省略。
- @Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用。
5.3 @Resource注入
5.3.1 @Resource注解和@Autowired注解的区别
- @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
- @Autowired注解是Spring框架自己的。
- @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
- @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。
- @Resource注解用在属性上、setter方法上。
- @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。
5.3.2 引入依赖
- @Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖
- JDK8不需要额外引入依赖
- 高于JDK11或低于JDK8需要引入以下依赖
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
5.3.3 @Resource声明
代码语言:javascript复制@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
enum AuthenticationType {
CONTAINER,
APPLICATION
}
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
}
5.3.4 实现
- UserDao
package com.example.dao;
public interface UserDao {
void out();
}
- UserDaoImpl
package com.example.dao.impl;
import com.example.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository(value="myUserDao")
public class UserDaoImpl implements UserDao {
@Override
public void out(){
System.out.println("user dao....");
}
}
- UserService
package com.example.service;
public interface UserService {
void out();
}
- UserServiceImpl
package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserServiceImpl implements UserService {
@Resource(name="myUserDao") // 根据name注入
private UserDao UserDao1;
@Resource
private UserDao myUserDao; // name未知注入,根据属性名注入
@Resource
private UserDao userDao; // 属性名找不到,根据类型注入
// 当UserDao有多个实现会报错
@Override
public void out() {
UserDao1.out();
myUserDao.out();
userDao.out();
}
}
- UserController
package com.example.controller;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
@Autowired
private UserService userService;
public void out(){
userService.out();
}
}
- bean.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 http://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.example"></context:component-scan>
</beans>
- ResourceTest
import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ResourceTest {
@Test
public void test(){
ApplicationContext app = new ClassPathXmlApplicationContext("bean.xml");
UserController bean = app.getBean(UserController.class);
bean.out();
}
}
5.4 全注解开发
- 全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文
- MainConfig
package com.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
//@ComponentScan({"com.example.controller","com.example.service","com.example.dao"})
@ComponentScan("com.example")
//@Import(DataSourceConfiguration.class) // 引入一个分配置
@Import({DataSourceConfiguration.class}) // 引入多个分配置
public class MainConfig {
}
- DataSourceConfiguration
package com.example.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
// <context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
@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("dataSource") // Spring会将当前方法的返回值以指定名称存储到Spring容器中
public DataSource f() throws PropertyVetoException {
// TODO 手动创建c3p0数据源
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(userName);
dataSource.setPassword(password);
return dataSource;
}
}
UserController
代码语言:javascript复制package com.example.controller;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Scope("prototype")
@Repository("myUserController")
public class UserController {
private String name;
public void out() {
System.out.println("out running....");
}
@PostConstruct
public void init(){
System.out.println("init method....");
}
@PreDestroy
public void destroy(){
System.out.println("destroy method....");
}
}
- AllAutoTest
import com.example.config.MainConfig;
import com.example.controller.UserController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MainConfig.class})
public class AllAutoTest {
@Autowired
private UserController userController;
@Test
public void test(){
userController.out();
System.out.println(userController);
}
}
5.5 Java反射
- Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。
- 引入依赖:lombok不用写get、set、toString、构造函数
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
- Car
package com.example.dao;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@ToString
@Data
public class Car {
/**
* 属性
*/
private String name;
private int age;
private String color;
/**
* 私有方法
*/
private void run() {
System.out.println("run.....");
}
}
- CarReflectTest
import com.example.dao.Car;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class CarReflectTest {
/**
* 1. 获取Class对象多种方式
*/
@Test
public void test01() throws Exception {
// 1. 类名.class
Class clazz1 = Car.class;
System.out.println("clazz1: " clazz1);
// 2. 对象.getClass()
Class clazz2 = new Car().getClass();
System.out.println("clazz2: " clazz2);
// 3. Class.forName("全路径")
Class clazz3 = Class.forName("com.example.dao.Car");
System.out.println("clazz3: " clazz3);
// 4. 实例化
Car car = (Car)clazz3.getConstructor().newInstance();
System.out.println(car);
}
/**
* 2. 获取构造方法
* @throws Exception
*/
@Test
public void test02() throws Exception {
Class clazz = Car.class;
// 1. 获取所有构造
// 1.1 getConstructors()获取所有public的构造方法
Constructor[] constructors = clazz.getConstructors();
System.out.println(Arrays.toString(constructors));
// 1.2 getDeclaredConstructors()获取所有的构造方法public private
Constructor[] constructors2 = clazz.getDeclaredConstructors();
for (Constructor c:constructors2) {
System.out.println("方法名称:" c.getName() " 参数个数:" c.getParameterCount());
}
// 2. 指定有参数构造创建对象
// 2.1 构造public
Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
Car car1 = (Car)c1.newInstance("夏利", 10, "红色");
System.out.println(car1);
// 2.2 构造private
Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
c2.setAccessible(true);
Car car2 = (Car)c2.newInstance("捷达", 15, "白色");
System.out.println(car2);
}
/**
* 3. 获取属性
*/
@Test
public void test03() throws Exception {
Class clazz = Car.class;
Car car = (Car)clazz.getDeclaredConstructor().newInstance();
// 获取所有public属性
Field[] fields = clazz.getFields();
System.out.println(Arrays.toString(fields));
// 获取所有属性(包含私有属性)
Field[] fields2 = clazz.getDeclaredFields();
for (Field field:fields2) {
if(field.getName().equals("name")) {
// 设置允许访问
field.setAccessible(true); // 不设置,会报错
field.set(car,"五菱宏光");
System.out.println(car);
}
System.out.println(field.getName());
}
}
/**
* 4. 获取方法
* @throws Exception
*/
@Test
public void test04() throws Exception {
Car car = new Car("奔驰",10,"黑色");
Class clazz = car.getClass();
// 1. public方法
Method[] methods = clazz.getMethods();
for (Method m1:methods) {
System.out.println("Car Method: " m1.getName());
// 执行方法 toString
if(m1.getName().equals("toString")) {
String invoke = (String)m1.invoke(car);
System.out.println("toString执行了:" invoke);
}
}
// 2. private方法
Method[] methodsAll = clazz.getDeclaredMethods();
for (Method m:methodsAll) {
// 执行方法 run
if(m.getName().equals("run")) {
m.setAccessible(true);
m.invoke(car);
}
}
}
}
5.6 实现Spring的IoC和DI
- MyDI注解
package com.example.spring.core.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD}) // Method declaration
@Retention(RetentionPolicy.RUNTIME)
public @interface MyDI {
}
- MyBean注解
package com.example.spring.core.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE) // ElementType.TYPE: Class, interface (including annotation type), or enum declaration // 能修饰类、接口、注解、枚举
@Retention(RetentionPolicy.RUNTIME)
public @interface MyBean {
}
- ApplicationContext接口
package com.example.spring.core;
public interface ApplicationContext {
Object getBean(Class clazz);
}
- AnnotationApplicationContext
package com.example.spring.core.impl;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import com.example.spring.core.ApplicationContext;
import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;
public class AnnotationApplicationContext implements ApplicationContext {
//存储bean的容器
private HashMap<Class, Object> beanFactory = new HashMap<>();
private static String rootPath;
@Override
public Object getBean(Class clazz) {
return beanFactory.get(clazz);
}
/**
* 根据包扫描加载bean
* @param basePackage
*/
public AnnotationApplicationContext(String basePackage) {
try {
String packageDirName = basePackage.replaceAll("\.", "\\");
Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
String filePath = URLDecoder.decode(url.getFile(),"utf-8");
rootPath = filePath.substring(0, filePath.length()-packageDirName.length());
loadBean(new File(filePath));
}
System.out.println(beanFactory);
} catch (Exception e) {
throw new RuntimeException(e);
}
//依赖注入
loadDi();
}
private void loadBean(File fileParent) {
if (fileParent.isDirectory()) {
File[] childrenFiles = fileParent.listFiles();
if(childrenFiles == null || childrenFiles.length == 0){
return;
}
for (File child : childrenFiles) {
if (child.isDirectory()) {
//如果是个文件夹就继续调用该方法,使用了递归
loadBean(child);
} else {
//通过文件路径转变成全类名,第一步把绝对路径部分去掉
String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
//选中class文件
if (pathWithClass.contains(".class")) {
// com.xinzhi.dao.UserDao
//去掉.class后缀,并且把 替换成 .
String fullName = pathWithClass.replaceAll("\\", ".").replace(".class", "");
try {
Class<?> aClass = Class.forName(fullName);
//把非接口的类实例化放在map中
if(!aClass.isInterface()){
MyBean annotation = aClass.getAnnotation(MyBean.class);
if(annotation != null){
Object instance = aClass.newInstance();
//判断一下有没有接口
if(aClass.getInterfaces().length > 0) {
//如果有接口把接口的class当成key,实例对象当成value
System.out.println("正在加载【" aClass.getInterfaces()[0] "】,实例对象是:" instance.getClass().getName());
beanFactory.put(aClass.getInterfaces()[0], instance);
}else{
//如果有接口把自己的class当成key,实例对象当成value
System.out.println("正在加载【" aClass.getName() "】,实例对象是:" instance.getClass().getName());
beanFactory.put(aClass, instance);
}
}
}
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
}
}
}
private void loadDi() {
for(Map.Entry<Class,Object> entry : beanFactory.entrySet()){
//就是咱们放在容器的对象
Object obj = entry.getValue();
Class<?> aClass = obj.getClass();
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields){
MyDI annotation = field.getAnnotation(MyDI.class);
if( annotation != null ){
field.setAccessible(true);
try {
System.out.println("正在给【" obj.getClass().getName() "】属性【" field.getName() "】注入值【" beanFactory.get(field.getType()).getClass().getName() "】");
field.set(obj,beanFactory.get(field.getType()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
- Brand
package com.example.dao;
import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;
import lombok.Data;
import lombok.ToString;
@MyBean
@Data
@ToString
public class Brand {
private String name;
}
- Car
package com.example.dao;
import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@ToString
@Data
@MyBean
public class Car {
/**
* 属性
*/
private String name;
private int age;
private String color;
@MyDI
private Brand brand;
/**
* 私有方法
*/
private void run() {
System.out.println("run.....");
}
}
- IoCTest
import com.example.dao.Car;
import com.example.spring.core.ApplicationContext;
import com.example.spring.core.impl.AnnotationApplicationContext;
import org.junit.Test;
public class IoCTest {
@Test
public void test(){
ApplicationContext app = new AnnotationApplicationContext("com.example");
Car car = (Car) app.getBean(Car.class);
System.out.println(car.getBrand());
}
}