IOC操作Bean管理
1.普通bean:在配置文件中定义bean类型就是返回类型
2.工厂bean:在配置文件定义bean类型可以和返回类型不一致
步骤:
--创建类,让这个类作为工厂bean,实现接口FactoryBean
--实现接口里的方法,在实现的方法定义返回的bean 类型
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
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">
<!--使用Spring创建对象,,即bean-->
<bean id="hello" class="com.wang.pojo.Hello">
<property name="name" value="spring"></property>
</bean>
</beans>
package com.wang.pojo;
import org.springframework.beans.factory.FactoryBean;
public class Hello implements FactoryBean<User> {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("hello"+this.name);
}
@Override
public User getObject() throws Exception {
User user = new User("wang",20);
return user;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
@Test
public void HelloTest(){
//获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//对象都在Spring中管理,使用时 直接取出即可
User hello = (User) context.getBean("hello");
System.out.println(hello);
}
Spring针对Bean管理中创建对象提供注解
- @Component
- @Service
- @Controller
- @Repository
*上面四个注解功能一样,都用来创建bean实例
基于注解创建Bean实例
<!--开启全包扫描:
扫描多个包,逗号隔开。
或者直接使用共同父包
-->
<context:component-scan base-package="com.wang"></context:component-scan>
<!--实例一:不使用默认的过滤器,中间代表自定义过滤器:只扫描Controller注解 -->
<context:component-scan base-package="com.wang" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 实例二:(排除)不扫描Controller -->
<context:component-scan base-package="com.wang" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
//注解中value可以省略,省略的话,默认值是类名(首字母小写)
@Component
public class UserService {
@Resource
UserDao userDao;
public void say(){
System.out.println("userService say....");
userDao.say();
}
}
将注解component换成以上任意一个都可以实现对象的创建
@Test
public void userService(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
context.getBean("userService", UserService.class).say();
}
基于注解方式实现属性的注入
@AutoWired:根据属性类型进行自动装配,所以不需set方法!!
@Qualifier:根据属性名称进行注入,要和AutoWired一起使用!
@Resource:根据类型注入,也可以根据名称注入(需要注意的是,Resource是javax扩展包中的,其他注解是Spring自带的)
@Value:根据普通类型注入
public interface UserDao {
public void say();
}
package com.wang.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImp implements UserDao{
@Override
public void say() {
System.out.println("dao say....");
}
}
@Service
public class UserService {
@Resource
UserDao userDao;
public void say(){
System.out.println("userService say....");
userDao.say();
}
}
完全注解开发
创建配置类,替代xml
原xml形式,里面只配置了扫描注解的路径,所以配置类中也只需要配置路径
package com.wang.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.wang"})//开启包内扫描
public class MyConfig {
}
@Test
public void userService(){
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
context.getBean("userService", UserService.class).say();
}
由读取xml文件改成读取配置类,其他保持不变
Bean的作用域
在Spring可以设置bean实例是单实例还是多实例:
Bean scope属性
默认单例模式,共享一个对象,scope=“singleton”
原型模式,scope=“prototype”
单例模式时,加载Spring配置文件时就会创建单实例对象
原型模式时,是每次在获取bean(getBean())新创建一个对象
Bean的生命周期
从对象的创建到对象销毁的过程
- 通过构造器(无参)去创建Bean实例
- 为Bean属性设置值和对其他Bean的引用(set的方法)
- 调用Bean里的初始化的方法(需要配置)
- Bean使用(获取到对象)
- 当容器关闭时,调用Bean的销毁方法(需要自己配置)
Spring中AOP(面向切编程)
对业务逻辑的各个部分进行隔离,从而使得业务了逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
不通过修改源代码方式,在主干功能里添加新功能
AOP底层使用动态代理的情况
- 有接口的情况,使用JDK动态代理
- 无接口的情况,使用CGLIB动态代理
JDK动态代理
场景分析:在不动底层代码的情况下,在用户登录之前去判断该用户的权限
public interface UserDao {
public void login(String name,String pwd);
}
package com.wang.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImp implements UserDao{
@Override
public void login(String name, String pwd) {
System.out.println("用户:"+name+"密码:"+pwd+"正在登录");
}
}
MyInvocationHandler中写增强方法的逻辑,即先获取被增强方法的类对象(userDao),为了方法的通用,使用Object,通过构造器在创建MyInvocationHandler对象时,将userDao传进来,method.invoke即利用反射去调用传进来对象(userDao)的指定方法,参数一该对象,参数二该方法的参数
public class MyInvocationHandler implements InvocationHandler {
Object obj;
public MyInvocationHandler(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("判断该用户的权限");
Object invoke = method.invoke(obj, args);
System.out.println("登陆成功!");
return null;
}
}
newProxyInstance(参数1,参数2,参数3)
- 类加载器
- 增强方法所在的类,这个类实现的接口,支持多个接口
- 实现接口InvocationHandler,创建代理对象,写增强的逻辑方法
@Test
public void userProxy(){
Class<?>[] a = new Class[]{UserDao.class};
UserDao o = (UserDao) Proxy.newProxyInstance(MyTest.class.getClassLoader(), a, new MyInvocationHandler(new UserDaoImp()));
o.login("wang","123");
}