Spring-IOC
IOC(控制翻转)的核心理念是将对象交由Spring容器来进行管理,Spring来管理对象的生成和装配,用户只用关心业务层的具体实现,而不用去管理对象的生命周期。
注册对象到容器中的方法有很多、最早都是在xml文件中配置的,后来为了简化开发,就出现了注解方式,二者本质是一样的。s
使用注解将对象加入到Spring容器中
使用注解的前提条件是开启注解支持和配置扫描包,下面提供两种方式:
-
xml方式的配置:
配置注解支持: <context:annotation-config/>
配置扫描包: <context:component-scan base-package=“com.java.**”/>
-
注解方式配置
配置扫描包:@ComponentScan()
开启注解支持:@EnableAutoConfiguration
-
注册bean到Spring容器中
@compoent: 用在类上,将该类加入到Spring容器中,这跟在xml文件中配置bean是一样的,spring容器中的bean的名称就是类名的小写。
@compoent的衍生注解:
1.dao层:@repository
2.service层:@service
3.controller层:@controller
这三个注解在本质上是没有区别的,都是将类加入到spring容器中,只是按照MVC三层架构来进行了区分。
-
依赖注入: Spring中IOC的具体实现就是依赖注入,依赖注入有三种方式
-
通过构造器的方式注入
@Service public class UserServiceImpl{ private UserMapper userMapper; //通过构造器的方式注入 public UserServiceImpl(UserMapper userMapper){ this.userMapper = userMapper; } }
-
通过set方法注入
@Service public class UserServiceImpl{ private UserMapper userMapper; //通过set方法注入 public void setUserMapper(userMapper userMapper){ this.user } }
-
使用注解注入
-
@autowired: 按照类型(类)来进行注入,如果用的时候在Spring中的上下文中找不到,会报空指针异常
-
@resource: 先按照名称来进行注入,如果找不到,再按照类型进行注入,如果两个都找不到会报错(功能强大,性能略微不如autowired)
@Qualifier(value=“xxx”),结合antowired使用,使用这个可以按照这个xxx名称去容器中寻找对应的bean
@Scope配置作用域:@Scope(“singleton”):单例模式容器中只有一个实例,spring容器中默认使用单例模式
@Scope(“prototype”):原型模式,每一个注入都会生成一个单独的bean
-
-
-
赋值操作
-
@Nullable添加这个注解,说明这个字段可以为空
-
@Value(“xxx”)给字段加上值
4. 配置
-
@ComponentScan:设置扫描包,去寻找需要注册到容器中的组件,通常在spingboot启动类中使用
-
@Configuration:在类上加上这个注解,就相当于xml中的,代表着一个配置类
然后需要写一个方法,在方法里面返回需要注册的bean,加上@bean注解
- 配置类写法
@Configuration @CompoentScan("com.java.openresource") public class testConfig{ @Bean public User getUser(){ return new User(); } } 注意:bean中注册的名字就是方法名,User中需要使用@Component注解,将该类加入到容器中 getUser等价于xml中id、返回值等价于class
- xml写法
<beans> <bean id="user" class="com.java.opensource.entity.user"> </bean> </beans>
以上两种写法是等价的!
Spring-AOP
Spring实现的核心是动态代理,学会代理思想可以加深对Spring AOP的理解
代理模式:
租房人、中介、房东(接口 真实角色 代理角色 客户端)
概述:现在有一个人想租房、还有一个房东想出租,这时候用户找不到房源,房东找不到客户,双方都达不到目的,于是中介就来了,中介承上启下,中介负责带我们看房,来办理合同相关事情, 房东只需按月收钱就行,不用关心跟客户对接的一大推事情,用户和房东的问题就得到了解决,这个中介其实就扮演了一个代理的角色。
代理模式优点:
1.可以使真实角色的操作更加纯粹,不用去关注公共的业务(房东只想租房出去,不想去看房什么的)
2.公共部分交给代理来使用(代理可以实现看房、联系管家等)
3.公共业务发生扩展的时候,方便集中管理
缺点:一个真实角色就会产生一个代理角色,代码量会翻倍。
1.静态代理:
静态代理就是重新实现一个接口,也就是创建一个代理类,然后去调用原来的实现类,在方法的前后加上特定内容,可以实现在不改变原有代码的基础上对方法进行增强。
缺点:不容易维护,当一个接口有多个实现类的时候,就要基于不同的实现类来进行编写特定的代理类、
2.动态代理:
一个动态代理类可以代理多个类,通常指的是一类业务,不用手动去实现代理类,操作简单,更容易维护,功能强大。
动态代理实现的代码实例:
需求:有一个用户接口,有增删改查四个操作,现在想通过动态代理的方法在执行每个方法前加上对应日志
//接口
public interface UserService {
void add();
void remove();
void update();
void query();
}
//实现类
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("实现了添加方法");
}
@Override
public void remove() {
System.out.println("实现了删除方法");
}
@Override
public void update() {
System.out.println("实现了修改方法");
}
@Override
public void query() {
System.out.println("实现了查询方法");
}
}
//代理调用处理器
public class ProxyInvokeHandler implements InvocationHandler {
//需要被代理的对象
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//动态生成代理对象
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
//返回执行结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
addOperateLog(method.getName());
return method.invoke(target, args);
}
private void addOperateLog(String operateStr) {
System.out.println("新增日志:执行了" + operateStr + "方法");
}
}
//执行测试
public class TestProxy {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
ProxyInvokeHandler proxyInvokeHandler = new ProxyInvokeHandler();
proxyInvokeHandler.setTarget(userService);
UserService proxy = (UserService) proxyInvokeHandler.getProxy();
proxy.remove();
}
}
-
aop底层包括很多框架的底层都是通过反射实现的
-
动态代理代理的是接口
-
动态代理有两种实现方式
- jdk自带的
- cglib实现的
这个可以去配置
动态代理是AOP的底层实现,实际使用中可以直接使用注解来进行开发
@Aspect:标记这个类为切面
-
@Before:在方法执行之前执行
-
@After:在方法执行之后执行
实例:@After(“execution(* com.java.opensource.UserServiceImpl.*(…)”);
@Aspect public class logConfig{ @After("execution(* com.java.opensource.UserServiceImpl.*(..)") public void addLog(){ System.out.print("在方法的执行之后添加一条日志信息"); } }
作用:执行UserServiceImpl中的任意方法时,会在方法执行完毕的时候增加一条这样的日志信息。
*(…)代表任何参数:具体参考execution表达式
以上就是本篇文章的全部内容了,如果想更深层次的了解Spring相关知识,我推荐这篇Spring中文文档、如果有问题,欢迎大家留言交流!