学过java的同学第一次在python中看到装饰器修饰函数或类时,第一时间想到的就是java中注解,如@Resource 可能会觉得它们是一样的,从我的理解来说,其实是完全不一样的两个东西。它们形似而神不同。
相同点
它们的作用都是一样的,可以通过它们在不改变原程序代码的情况下,给程序增加一些新的功能,实现AOP。
不同点
注解在文档中的解释是一个‘’标志‘’它的本质是用来给java编译器“看”的注释,在java程序运行时,通过反射查找特定的‘’标志‘’,将此标志作为判断条件,做一些操作;
装饰器的本质是一个函数,闭包函数,将被装饰函数的地址,一般用与被装饰函数相同的名字‘’李代桃僵‘’,调用的其实是装饰器函数反回的函数地址。
看看它们的使用吧
装饰器的使用
import time
# 定义一个装饰器,增加打印程序运行时间的功能
# 小提示,python是解释性语言,从上而下执行代码,装饰器要写在被装饰函数的前面
def outter(func):
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs) # 解构
stop = time.time()
print(stop - start)
return res, stop - start # 返回被装饰对象的返回值
return wrapper
@outter # 在被装饰对象正上方单独一行写@装饰器名(语法糖),等同于index=outter(index)
def index(x, y):
time.sleep(3)
print("index %s,%s" % (x, y))
if __name__ == '__main__':
res = index(1, 3)
print(res)
程序运行结果
index 1,3
3.0063154697418213
(None, 3.0063154697418213)
注解的使用
模拟spring创建单例和多例对象
1. 定义一个扫描注解
ComponentScan
package com.zhaojun.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义扫描路径注解
*/
@Retention(RetentionPolicy.RUNTIME)//注解的作用时间,程序运行时
@Target(ElementType.TYPE)//注解使用范围
public @interface ComponentScan {
String value() default "";
}
2. 定义一个配置类
AppConfig
package com.zhaojun.service;
import com.zhaojun.spring.ComponentScan;
@ComponentScan("com.zhaojun.service")
public class AppConfig {
}
3. 定义一个Bean注解
Component
package com.zhaojun.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义Bean注解
*/
@Retention(RetentionPolicy.RUNTIME)//运行时
@Target(ElementType.TYPE)//注解使用范围
public @interface Component {
String value() default "";
}
4. 定义一个Scope注解
package com.zhaojun.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 单例Bean或多例Bean
*/
@Retention(RetentionPolicy.RUNTIME)//运行时
@Target(ElementType.TYPE)//注解使用范围
public @interface Scope {
String value() default "";
}
5. 定义一个类,模拟spring容器
package com.zhaojun.spring;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
/**
* 自定义Spring容器
*/
public class ZhaojunApplicationContext {
private Class configClass;
private ConcurrentHashMap<String,BeanDefinition> beanDefinitipnMap=new ConcurrentHashMap<>();
private ConcurrentHashMap<String,Object> singleObjects=new ConcurrentHashMap<>();//单例Bean池
public ZhaojunApplicationContext(Class configClass) {
this.configClass = configClass;
//扫描
if(configClass.isAnnotationPresent(ComponentScan.class)){
ComponentScan componentScanAnnotation = (ComponentScan)configClass.getAnnotation(ComponentScan.class);
//获取注解中配置的路径 com.zhaojun.service
String path = componentScanAnnotation.value();
path=path.replace(".","/");//com/zhaojun/service
ClassLoader classLoader = ZhaojunApplicationContext.class.getClassLoader();
//从classpath中获取class文件路径
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());//获取到指定文件夹或文件
if (file.isDirectory()){
File[] files = file.listFiles();
for (File f:files){
String fileName = f.getAbsolutePath();
if (fileName.endsWith(".class")){
//转换全类名
URL resource1 = ZhaojunApplicationContext.class.getResource("/");
String path1 = resource1.getPath();
String className = fileName.substring(path1.length()-1); //com\zhaojun\service\AppConfig.class
//拿捏类名 com.zhaojun.service.AppConfig
String replace = className.substring(0, className.indexOf(".class")).replace("\\", ".");
try {
Class<?> clazz = classLoader.loadClass(replace);
if (clazz.isAnnotationPresent(Component.class)){
//获取bean的名字
Component component = clazz.getAnnotation(Component.class);
String beanName = component.value();
//BeanDefinition
BeanDefinition beanDefinition=new BeanDefinition();
beanDefinition.setType(clazz);
//判断多例还是单例Bean
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
String scop = scopeAnnotation.value();
beanDefinition.setScope(scop);
}else{
beanDefinition.setScope("singleton");
}
//保存Bean
beanDefinitipnMap.put(beanName,beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
//实例化单例Bean
for (String beanName : beanDefinitipnMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitipnMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")){
Object bean = createBean(beanName,beanDefinition);
singleObjects.put(beanName,bean);
}
}
}
//创建对象
private Object createBean(String beanName,BeanDefinition beanDefinition){
Class clazz = beanDefinition.getType();
try {
Object instance = clazz.getConstructor().newInstance();//调无参构造创建实例
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
//自定义getBean方法
public Object getBean(String beanName){
BeanDefinition beanDefinition = beanDefinitipnMap.get(beanName);
if(beanDefinition==null){
throw new NullPointerException();
}else{
String scope = beanDefinition.getScope();
if(scope.equals("singleton")){
Object bean = singleObjects.get(beanName);
if(bean==null){
Object o = createBean(beanName, beanDefinition);
singleObjects.put(beanName,o);
}
return bean;
}else{
//多例
return createBean(beanName, beanDefinition);
}
}
}
}
6. 创建一个类,用来测试
package com.zhaojun.service;
import com.zhaojun.spring.Component;
import com.zhaojun.spring.Scope;
@Component("userService")
@Scope("prototype")
public class UserService {
}
7. 测试
package com.zhaojun.service;
import com.zhaojun.spring.ZhaojunApplicationContext;
public class Test {
public static void main(String[] args) {
ZhaojunApplicationContext zhaojunApplicationContext = new ZhaojunApplicationContext(AppConfig.class);
System.out.println(zhaojunApplicationContext.getBean("userService"));
System.out.println(zhaojunApplicationContext.getBean("userService"));
System.out.println(zhaojunApplicationContext.getBean("userService"));
System.out.println(zhaojunApplicationContext.getBean("userService"));
}
}