feat: support Autowired and JSClass inject

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
MiaoWoo 2020-06-17 18:34:01 +08:00
parent 32db0bba56
commit 8a07e85fda
4 changed files with 135 additions and 61 deletions

View File

@ -25,6 +25,7 @@
}, },
"dependencies": { "dependencies": {
"inversify": "^5.0.1", "inversify": "^5.0.1",
"inversify-binding-decorators": "^4.0.0" "inversify-binding-decorators": "^4.0.0",
"@ccms/nashorn": "^0.7.0"
} }
} }

View File

@ -0,0 +1,7 @@
export namespace ioc {
export const Autowired = Symbol('Autowired')
export const Resource = Symbol('Resource')
export const JavaClass = Symbol('JavaClass')
export const JavaInstance = Symbol('JavaInstance')
export const JavaStaticClass = Symbol('JavaStaticClass')
}

View File

@ -1,9 +1,9 @@
import { interfaces, Container } from "inversify"; import { interfaces, Container } from "inversify"
let _container: Container; let _container: Container
const ContainerInstance = Symbol.for("@ccms/ioc:Container"); const ContainerInstance = Symbol.for("@ccms/ioc:Container")
const INJECTION = Symbol.for("INJECTION"); const INJECTION = Symbol.for("INJECTION")
function _proxyGetter( function _proxyGetter(
proto: any, proto: any,
@ -13,17 +13,17 @@ function _proxyGetter(
) { ) {
function getter(this: object) { function getter(this: object) {
if (doCache && !Reflect.hasMetadata(INJECTION, this, key)) { if (doCache && !Reflect.hasMetadata(INJECTION, this, key)) {
Reflect.defineMetadata(INJECTION, resolve(), this, key); Reflect.defineMetadata(INJECTION, resolve(), this, key)
} }
if (Reflect.hasMetadata(INJECTION, this, key)) { if (Reflect.hasMetadata(INJECTION, this, key)) {
return Reflect.getMetadata(INJECTION, this, key); return Reflect.getMetadata(INJECTION, this, key)
} else { } else {
return resolve(); return resolve()
} }
} }
function setter(this: object, newVal: any) { function setter(this: object, newVal: any) {
Reflect.defineMetadata(INJECTION, newVal, this, key); Reflect.defineMetadata(INJECTION, newVal, this, key)
} }
Object.defineProperty(proto, key, { Object.defineProperty(proto, key, {
@ -31,63 +31,63 @@ function _proxyGetter(
enumerable: true, enumerable: true,
get: getter, get: getter,
set: setter set: setter
}); })
} }
function initContainer(container: Container) { function initContainer(container: Container) {
Reflect.defineMetadata(ContainerInstance, container, Reflect); Reflect.defineMetadata(ContainerInstance, container, Reflect)
_container = container; return _container = container
} }
function getContainer(): Container { function getContainer(): Container {
return _container || Reflect.getMetadata(ContainerInstance, Reflect) return _container || initContainer(new Container())
} }
function makePropertyInjectDecorator(doCache: boolean) { function makePropertyInjectDecorator(doCache: boolean) {
return function(serviceIdentifier: interfaces.ServiceIdentifier<any>) { return function (serviceIdentifier: interfaces.ServiceIdentifier<any>) {
return function(proto: any, key: string): void { return function (proto: any, key: string): void {
let resolve = () => { let resolve = () => {
return getContainer().get(serviceIdentifier); return getContainer().get(serviceIdentifier)
}; }
_proxyGetter(proto, key, resolve, doCache); _proxyGetter(proto, key, resolve, doCache)
}; }
}; }
} }
function makePropertyInjectNamedDecorator(doCache: boolean) { function makePropertyInjectNamedDecorator(doCache: boolean) {
return function(serviceIdentifier: interfaces.ServiceIdentifier<any>, named: string) { return function (serviceIdentifier: interfaces.ServiceIdentifier<any>, named: string) {
return function(proto: any, key: string): void { return function (proto: any, key: string): void {
let resolve = () => { let resolve = () => {
return getContainer().getNamed(serviceIdentifier, named); return getContainer().getNamed(serviceIdentifier, named)
}; }
_proxyGetter(proto, key, resolve, doCache); _proxyGetter(proto, key, resolve, doCache)
}; }
}; }
} }
function makePropertyInjectTaggedDecorator(doCache: boolean) { function makePropertyInjectTaggedDecorator(doCache: boolean) {
return function(serviceIdentifier: interfaces.ServiceIdentifier<any>, key: string, value: any) { return function (serviceIdentifier: interfaces.ServiceIdentifier<any>, key: string, value: any) {
return function(proto: any, propertyName: string): void { return function (proto: any, propertyName: string): void {
let resolve = () => { let resolve = () => {
return getContainer().getTagged(serviceIdentifier, key, value); return getContainer().getTagged(serviceIdentifier, key, value)
}; }
_proxyGetter(proto, propertyName, resolve, doCache); _proxyGetter(proto, propertyName, resolve, doCache)
}; }
}; }
} }
function makePropertyMultiInjectDecorator(doCache: boolean) { function makePropertyMultiInjectDecorator(doCache: boolean) {
return function(serviceIdentifier: interfaces.ServiceIdentifier<any>) { return function (serviceIdentifier: interfaces.ServiceIdentifier<any>) {
return function(proto: any, key: string): void { return function (proto: any, key: string): void {
let resolve = () => { let resolve = () => {
return getContainer().getAll(serviceIdentifier); return getContainer().getAll(serviceIdentifier)
}; }
_proxyGetter(proto, key, resolve, doCache); _proxyGetter(proto, key, resolve, doCache)
}; }
}; }
} }
let doCache = true; let doCache = true
let lazyInject = makePropertyInjectDecorator(doCache) let lazyInject = makePropertyInjectDecorator(doCache)
let lazyInjectNamed = makePropertyInjectNamedDecorator(doCache) let lazyInjectNamed = makePropertyInjectNamedDecorator(doCache)
@ -102,4 +102,4 @@ export {
lazyInjectNamed, lazyInjectNamed,
lazyInjectTagged, lazyInjectTagged,
lazyMultiInject lazyMultiInject
}; }

View File

@ -1,25 +1,91 @@
import "reflect-metadata"; /// <reference types="@ccms/nashorn" />
import { initContainer } from './decorators'
import { interfaces, Container } from 'inversify';
import { fluentProvide } from 'inversify-binding-decorators';
const provideNamed = (identifier: interfaces.ServiceIdentifier<any>, name: string) => { import "reflect-metadata"
return fluentProvide(identifier).whenTargetNamed(name).done(); import { initContainer, getContainer } from './decorators'
}; import { interfaces, Container } from 'inversify'
import { fluentProvide } from 'inversify-binding-decorators'
import { ioc } from "./constants"
const provideSingleton = (identifier: interfaces.ServiceIdentifier<any>) => { /**
return fluentProvide(identifier).inSingletonScope().done(); *
}; * @param identifier
* @param name
*/
export const provideNamed = (identifier: interfaces.ServiceIdentifier<any>, name: string) => {
return fluentProvide(identifier).whenTargetNamed(name).done()
}
const DefaultContainer = new Container(); /**
initContainer(DefaultContainer); *
* @param identifier
*/
export const provideSingleton = (identifier: interfaces.ServiceIdentifier<any>) => {
return fluentProvide(identifier).inSingletonScope().done()
}
/**
*
* @param identifier
*/
export const provideSingletonNamed = (identifier: interfaces.ServiceIdentifier<any>, name: string) => {
return fluentProvide(identifier).inSingletonScope().whenTargetNamed(name).done()
}
/**
* java.lang.Class
* @param className Java全类名
*/
export const JavaClass = (className: string) => {
return function (target: any, propertyKey: string, index?: number) {
try { target[propertyKey] = Java.type(className).class; return } catch (error) { }
try { target[propertyKey] = base.getClass(className); return } catch (error) { }
console.warn('JavaClass Inject target', target, 'propertyKey', propertyKey, 'failed!')
}
}
/**
* JS的Java类
* @param className Java
*/
export const JSClass = (className: string) => {
return function (target: any, propertyKey: string, index?: number) {
try { target[propertyKey] = Java.type(className); return } catch (error) { }
try { target[propertyKey] = base.getClass(className).static; return } catch (error) { }
console.warn('JSClass Inject target', target, 'propertyKey', propertyKey, 'failed!')
}
}
/**
*
* @param className
*/
export const Autowired = (className?: string | any) => {
return function (target: any, propertyKey: string) {
target[propertyKey] = getContainer().getNamed(ioc.Autowired, className || propertyKey)
}
}
/**
*
* @param className
*/
export const Resource = (resourceName?: string | any) => {
return function (target: any, propertyKey: string) {
target[propertyKey] = getContainer().getNamed(ioc.Resource, resourceName || propertyKey)
}
}
export const reduceMetadata = (ctx: interfaces.Context): any => {
return ctx.currentRequest.target.metadata.reduce((result, entry, index) => {
result[entry.key] = entry.value
return result
}, {})
}
export const DefaultContainer = new Container()
initContainer(DefaultContainer)
export * from 'inversify' export * from 'inversify'
export * from './constants'
export * from './decorators' export * from './decorators'
export * from 'inversify-binding-decorators' export * from 'inversify-binding-decorators'
export {
fluentProvide,
provideNamed,
provideSingleton,
DefaultContainer
};